Go数据结构

(8)Go实现二分搜索树-删除任意节点

2019-04-20  本文已影响1人  哥斯拉啊啊啊哦

https://www.jianshu.com/p/de46dcebada3
继上一篇《Go--二分搜索树1--前中后序递归》的后续

找出最小值,最大值,删除最小值,最大值,删除任意节点的非递归算法和递归算法实现
// 找出最小值,并将该值返回,非递归算法
func (tree *node) FindMinVal() *int {
    if tree.value == nil {
        return nil
    }

    buf := tree
    for {
        if buf.Left.value == nil {
            return buf.value
        }
        buf = buf.Left
    }
}

// 找出最小值,并将该值返回,递归算法
func (tree *node) FindMinVal2() *int {
    if tree.Left.value == nil {
        return tree.value
    }

    return tree.Left.FindMinVal2()
}

// 找出最大值,并将该值返回,非递归算法
func (tree *node) FindMaxVal() *int {
    if tree.value == nil {
        return nil
    }

    for {
        if tree.Right.value == nil {
            return tree.value
        }
        tree = tree.Right
    }
}

// 找出最大值,并将该值返回,递归算法
func (tree *node) FindMaxVal2() *int {
    if tree.Right.value == nil {
        return tree.value
    }

    return tree.Right.FindMaxVal2()
}

// 删除最小值并将该值返回,非递归算法
func (tree *node) DeleteMinVal() *int {
    if tree.value == nil {
        return nil
    }

    for {
        if tree.Left.value == nil {
            v := tree.value

            // 这里如果写成 tree = tree.Right 执行后外面tree不会变
            *tree = *tree.Right
            return v
        }
        tree = tree.Left
    }
}

// 删除最小值并将该值返回,递归算法
func (tree *node) DeleteMinVal2() *int {
    if tree.value == nil {
        return nil
    }

    if tree.Left.value == nil {
        v := tree.value
        *tree = *tree.Right
        return v
    }
    return tree.Left.DeleteMinVal2()
}

// 删除最大值并将该值返回,非递归算法
func (tree *node) DeleteMaxVal() *int {
    //if tree.value == nil {
    //  return nil
    //}

    for {
        if tree.Right.value == nil {
            v := tree.value
            *tree = *tree.Left
            return v
        }
        tree = tree.Right
    }
}

// 删除最大值并将该值返回,递归算法
func (tree *node) DeleteMaxVal2() *int {
    if tree.value == nil {
        return nil
    }

    if tree.Right.value == nil {
        v := tree.value
        *tree = *tree.Left
        return v
    }
    return tree.Right.DeleteMaxVal2()
}
删除搜索树的任意节点分为以下几种情况:
(1)节点为叶子节点,直接将该节点删除;
(2)节点只有左子树右子树为空,则将该节点的左子树替换到该节点位置,即 tree = tree.left;
(3)节点只有右子树左子树为空,则将该节点的右子树替换到该节点位置,即 tree = tree.right;
(4)节点左右子树都不为空,解决方法由两种:
        1):节点值替换为右子树中的最小值,并将右子树中的最小值删除;
        2):节点值替换为左子树中的最大值,并将左子树中的最大值删除;

// 删除给定的值,非递归算法
func (tree *node) DeleteChoose(val *int) {
    for {
        switch {
        // 这里包含两种情况,val不在tree里面,或者tree.value=nil
        case tree.value == nil:
            return
        //  
        case *tree.value == *val:
            if tree.Right.value == nil {
                // 这里包含2中情况,left为nil和不为nil
                *tree = *tree.Left
                return
            }
            // DeleteMinVal():删除tree中的最小值,并将最小值返回
            tree.value = tree.Right.DeleteMinVal()
            return
        case *tree.value > *val:
            tree = tree.Left
        case *tree.value < *val:
            tree = tree.Right
        }
    }
}

// 删除给定的值,递归算法
func (tree *node) DeleteChoose2(val *int) {
    // 如果不加这个判定,删除的数值不在tree里面会报错
    if tree.value == nil {
        return
    }

    if *tree.value == *val {
        // DeleteMinVal2():删除tree中的最小值,并将最小值返回
        tree.value = tree.Right.DeleteMinVal2()
        return
    }

    if *tree.value > *val {
        tree.Left.DeleteChoose2(val)
        return
    }
    if *tree.value < *val {
        tree.Right.DeleteChoose2(val)
    }
}
测试算法
先定义一个tree的中序遍历打印方法
// 中序遍历打印tree
func (tree *node) Print() {
    buf := []int{}
    tree.TraverseInOrder(&buf)
    fmt.Println("中序遍历结果:", buf)
}

测试代码
func main() {
    b := fork_tree1.NewNode()
    b.Add2(20)
    for i := 0; i < 20; i++ {
        b.Add2(rand.Intn(40))
    }

    b.Print()
    fmt.Printf("非递归找出最小值:%d\n", *b.FindMinVal())
    fmt.Printf("递归找出最小值:%d\n", *b.FindMinVal2())
    fmt.Printf("非递归找出最大值:%d\n", *b.FindMaxVal())
    fmt.Printf("递归找出最大值:%d\n", *b.FindMaxVal2())
    b.Print()
    fmt.Println("--------")
    fmt.Printf("非递归删除最小值:%d\n", *b.DeleteMinVal())
    b.Print()
    fmt.Printf("递归删除最小值:%d\n", *b.DeleteMinVal2())
    b.Print()
    fmt.Printf("非递归删除最大值:%d\n", *b.DeleteMaxVal())
    b.Print()
    fmt.Printf("递归删除最大值:%d\n", *b.DeleteMaxVal2())
    b.Print()
    fmt.Println("--------")
    v1 := 40
    v2 := 20
    b.DeleteChoose(&v1)
    fmt.Println("非递归删除40:")
    b.Print()
    b.DeleteChoose(&v2)
    fmt.Println("非递归删除20:")
    b.Print()
    v1 = 36
    v2 = 14
    b.DeleteChoose2(&v1)
    fmt.Println("递归删除36:")
    b.Print()
    b.DeleteChoose2(&v2)
    fmt.Println("递归删除14:")
    b.Print()
}
测试输出结果
中序遍历结果: [1 2 5 7 8 9 11 14 16 19 20 25 26 31 34 37 38]
非递归找出最小值:1
递归找出最小值:1
非递归找出最大值:38
递归找出最大值:38
中序遍历结果: [1 2 5 7 8 9 11 14 16 19 20 25 26 31 34 37 38]
--------
非递归删除最小值:1
中序遍历结果: [2 5 7 8 9 11 14 16 19 20 25 26 31 34 37 38]
递归删除最小值:2
中序遍历结果: [5 7 8 9 11 14 16 19 20 25 26 31 34 37 38]
非递归删除最大值:38
中序遍历结果: [5 7 8 9 11 14 16 19 20 25 26 31 34 37]
递归删除最大值:37
中序遍历结果: [5 7 8 9 11 14 16 19 20 25 26 31 34]
--------
非递归删除40:
中序遍历结果: [5 7 8 9 11 14 16 19 20 25 26 31 34]
非递归删除20:
中序遍历结果: [5 7 8 9 11 14 16 19 25 26 31 34]
递归删除36:
中序遍历结果: [5 7 8 9 11 14 16 19 25 26 31 34]
递归删除14:
中序遍历结果: [5 7 8 9 11 16 19 25 26 31 34]
//
二分搜索树的时间复杂度分析
h 表示二分搜索数的高度,n 表示节点数量
对于满的二分搜索数,h = log2(n+1) = O(log2(n))
增add:O(h)        查contains:O(h)        删del:O(h)
logn 和 n 的差距
            logn    n
n =16       4       16      相差4倍
n =1024     10      1024    相差100倍
n =100万    20      100万    相差5万倍

logn是平均的情况,在最坏的情况下,搜索树只有单边
有数据,这样节点数量会等于高度,即n=h,在最坏的
情况下,时间复杂度为O(n)
解决这种情况的方法是平衡二叉树,待更新...

有bug欢迎指出,转载请注明出处。

上一篇 下一篇

猜你喜欢

热点阅读