茶艺师学算法打卡11:二叉树

142 阅读4分钟

茶艺师学算法打卡11:二叉树

学习笔记

二叉树

二叉树是树(tree)的一种,具体来说是最多只有左子节点与右子节点的树。
除了叶子节点,所有节点都有左子节点与右子节点,这二叉树就是满二叉树
叶子节点分布在最底一层和倒数第二层,且最底一层的叶子节点都靠左排列,这样的树是完全二叉树
【图 满二叉树 完全二叉树】
完全二叉树为何完全,要看看二叉树如何存。
通用的存法是用链表法,如:

type treeNode struct {
    val int 
    left *treeNode 
    right *treeNode
}

但是完全二叉树与满二叉树能用数组存,如:

树的根存在数组下标“1”的位置,对于一个下标为 x 的节点 i,它其他节点可以通过计算下标得出:

  • 下标 2x 处存的是 i 的左子节点
  • 下标 2x + 1 处存的是 i 的右子节点
  • 下标 x/2 处存的是 i 的父节点

这里就能理解为什么“完全”了,完全二叉树存成数组,就是一个不会有空的数组。
二叉树有不少遍历方法,最耳熟能详的就是这么三个:前序遍历,中序遍历,后序遍历。
其中的“序”,是指根节点什么时候遍历。

// 前序遍历
func perCal(root *treeNode) {
    if root == nil {
        return 
    }
    print(root.Val) // 遍历根
    perCal(root.Left)
    perCal(root.Right)
}
// 中序遍历
func midCal(root *treeNode) {
    if root == nil {
        return 
    }
    midCal(root.Left)
    print(root.Val) // 遍历根
    midCal(root.Right)
}
// 后序遍历
func posCal(root *treeNode) {
    if root == nil {
        return 
    }
    posCal(root.Left)
    posCal(root.Right)
    print(root.Val) // 遍历根
}

在代码上也能很直观得看出根是在什么时候遍历,而且这样的遍历也很适合用递归来写。

二叉搜索树

二叉搜索树是二叉树的一种,它的特点是,某节点 i ,与左右子节点 left 、 right ,要满足这样的关系:left.Val<i.Vali.Val<right.Valleft.Val < i.Val , i.Val < right.Val
因此有着这样的特性:当用中序遍历一个二叉搜索树时,就能得到一个有序序列。
二叉搜索树被设计出来是为了快速查找,实际上它也支持快速插入、删除数据。其操作的简单思路是:

  • 查找 先比较根的值,如果比根的值大,就递归查找右子树,否则就递归查找左子树
  • 插入 先把值插入叶子节点,然后比较它的根的值。如果比根小,且根没有左子节点,就直接挪到那里去,不然就递归遍历它的左子树;反之亦然。
  • 删除 这就有点麻烦,得考虑三种情况:要删除的点没有子节点、有一个子节点、有两个子节点。没有子节点的,直接删掉就是了;有一个子节点的,就把要删除节点的父节点连到要删除节点的子节点,再把这个节点删掉就行了;有两个子节点的,先找到待删除节点的右子树里的最小节点,两者替换,再把**替换后的“最小节点(待删除节点)”**删掉就行了。

对二叉搜索树稍微改造一下,也能支持存同样数值。改造思路有二:

  • 思路1 用链表法存一对数据
  • 思路2 每个节点仍存一个数据,但是遇到相同的数据,直接存到这个节点的右边,即 left.Val<i.Vali.Val<=right.Valleft.Val < i.Val , i.Val <= right.Val

如果二叉搜索树能保持平衡,不退化成链表,它的查找、插入、删除的耗时是 O(树的高度)O(树的高度) ,即 O(logn)O(logn) ,乍一看哈希表都是完胜。
但哈希表就是代替不了二叉搜索树,理由主要有:

  • 哈希表只能存无序的数据,二叉搜索树用 O(n)O(n) 时间中序遍历就能获得有序数据

  • 哈希表的扩容很耗时间,如果触发了哈希碰撞,哈希表的性能会不稳定。但二叉搜索树(平衡)能稳定在 O(logn)O(logn)

  • 二叉搜索树(平衡)的 O(logn)O(logn) 与哈希表的 O(1)O(1) ,表面看着是哈希表更优秀,在实际用起来,两者差不了多少

  • 哈希表要考虑很多东西,如设计好的哈希函数、冲突解决办法、扩容与缩容方案等。而二叉搜索树(平衡)只需要考虑如何保持它的平衡。