树——二叉排序树(BST)

二叉排序树

  1. 概念
  2. 查找
  3. 插入
  4. 删除(难点)

1、概念

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

注:二叉树的中序遍历结果是一个有序数列

2、查找

        给定一个数组,把它变为二叉搜索树

  先定义二叉树结构:

type LinkNode struct{
    Val int
    Left *LinkNode
    Right *LinkNode
}

 注:二叉排序树最好情况为:完全二叉树 O(logn)

                          最坏情况为:退化为单链表O(n)

 二叉树查找:

// 查找
// 类似二分查找的树化
func (root *LinkNode) SearchTree(targer int) *LinkNode {
	if root == nil {
		return nil
	}
	for root != nil {
		if root.Val > targer {
			root = root.Left
		} else if root.Val < targer {
			root = root.Right
		} else {
			return root
		}
	}
	return nil
}

3、插入

// 插入数据
// 如果插入的元素已存在,直接返回false
// 需要随时记录父节点的位置
func (root *LinkNode) insertTree(targer int) bool {
	node := &LinkNode{Val: targer}
	if root == nil {
		root.Val = targer
	}
	var parent *LinkNode
	cur := root
	for cur != nil {
		if cur.Val == targer {			// 有重复元素则返回
			return false
		} else if cur.Val > targer {	
			parent = cur				// 保留当前节点
			cur = cur.Left
		} else {
			parent = cur
			cur = cur.Right
		}
	}
	if parent.Val > targer {
		parent.Left = node
	} else {
		parent.Right = node
	}
	return true
}

4、删除

有两种情况

  1. 被删除节点:左孩子存在,右孩子为空 或者 右孩子存在左孩子为空
  2. 被删除节点:左孩子右孩子都不为空

     解决:

        第一种情况直接让左/右孩子直接代替被删除节点

        第二种情况需要进行 旋转 处理!!!

func (root *LinkNode) remove(targer int) bool {
	if root == nil { // 树为空,不存在要删除的节点
		return false
	}

	var parent *LinkNode // 被删除节点的父节点
	cur := root          // 复制一份
	for cur != nil {
		if cur.Val == targer {
			removeKey(parent, cur)
			return true
		} else if cur.Val > targer {
			parent = cur
			cur = cur.Left
		} else {
			parent = cur
			cur = cur.Right
		}
	}
	return false
}

// 处理三种情况(其中两种类似)
func (root *LinkNode) removeKey(parent *LinkNode, cur *LinkNode) {
	if cur.Left == nil { 				// 被刪除节点左孩子为空
		if cur == root { 				// 被删除节点为 根节点
			root = root.Right
		} else if cur == parent.Left { 	// 被删除节点 在父节点的左边
			parent.Left = cur.Right
		} else { 						// 被删除节点 在父节点的右边
			parent.Right = cur.Right
		}
	} else if cur.Right == nil {
		if cur == root {
			root = root.Left
		} else if cur == parent.Left {
			parent.Left = cur.Left
		} else {
			parent.Right = cur.Left
		}
	} else { 						// 处理最复杂的情况。被删除节点左右孩子都不为空
		// 一般取被删除节点的右孩子的最小值,替换被删除节点
		parentNode := cur    		// 保存被删除的节点
		minNode := cur.Right 		// 获取被删除节点的右节点(被删除节点的右孩子)
		for parentNode != nil {
			parentNode = minNode
			minNode = minNode.Left
		}
		// 找到合适的节点(右孩子的最小值)
		cur.Val = minNode.Val
		if parentNode.Left == minNode {
			parentNode.Left = minNode.Right
		} else {
			parentNode.Right = minNode.Right	// 用于处理右孩子为单链表结构
		}

	}
}

验证:中序遍历

// 中序遍历 用于验证是否成功
func (root *LinkNode) midPrint() []int {
	var res []int
	var dfs func(*LinkNode)
	dfs = func(root *LinkNode) {
		if root == nil {
			return
		}

		if root.Left != nil {
			dfs(root.Left)
		}
		res = append(res, root.Val)
		if root.Right != nil {
			dfs(root.Right)
		}
	}
	dfs(root)
	return res
}

func main() {
    // 构建二叉树
	root := &LinkNode{Val: 4}
	root2 := &LinkNode{Val: 2}
	root3 := &LinkNode{Val: 6}
	root4 := &LinkNode{Val: 1}
	root5 := &LinkNode{Val: 5}
	root6 := &LinkNode{Val: 7}
	root.Left = root2
	root.Right = root3
	root2.Left = root4
	root3.Left = root5
	root3.Right = root6

	fmt.Println(root.SearchTree(8))    // 查找元素 8
	res := root.midPrint()             
	fmt.Println(res)                   // 打印中序遍历的二叉树
	fmt.Println(root.insertTree(10))   // 插入元素10
	fmt.Println(root.remove(4))        // 删除元素4(根节点)
	res = root.midPrint()                
	fmt.Println(res)                   // 打印中序遍历的二叉树
}

结果:

<nil>
[1 2 4 5 6 7]
true        // 插入成功
true        // 删除成功
[1 2 5 6 7 10]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值