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

https://blog.csdn.net/weixin_43456598/article/details/100538627
继上一篇《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.value == nil {
		return nil
	}

	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 =10020	    100万	相差5万倍

logn是平均的情况,在最坏的情况下,搜索树只有单边有数据,
这样节点数量会等于高度,即n=h,在最坏的情况下,时间复杂度为O(n)
避免单边有数据的情况的方法是用平衡二叉树,如AVL树,或红黑树
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值