算法导论(九)--二叉树

二叉搜索树

(BST,Binary Search Tree,也叫二叉排序树,Binary Sort Tree)

BST Sort

二叉搜索树的定义就不讲了。我们看看BST Sort,如何利用二叉树进行排序?答案是只要把数组构建出一棵二叉搜索树,然后中序遍历就行了。
构建二叉搜索树的算法:

T<-Ø
for i<-i to n
	do Tree_Insert_Walk(T,A[i])
InOrder-Tree(T->root)

举例:
数组A={3,1,8,2,6,7,5},构造二叉搜索树,然后中序遍历依次打印出来。
在这里插入图片描述
分析这个算法的复杂度。遍历需要O(n)。

如果构造的是下面这样的完全平衡的二叉树,那么n次插入需要Ω(nlog),因为每次插入都需要查找,所有节点的深度加起来就是总的查询时间,看最底层有n/2个节点,每个节点的深度都是logn,所以是至少是O(nlogn)。
在这里插入图片描述
如果数组已经是有序的了,那么就会构造出下面这样的树,总的花费时间还是树中每个节点深度的总和,就是1+2+3+…,等差级数,就是Θ(n2)。
在这里插入图片描述

与快排的关系

简单快排
这个算法跟快排很类似,它们其实做的是相同的比较,只是比较的顺序不一样。对数组A={3,1,8,2,6,7,5}做最简单的快排,先不改变两边元素的顺序,过程如下图所示:
在这里插入图片描述
我们通过划分得到的树与上面得到的二叉搜索树其实就是同一棵树。

Randomized BST Sort
如果是随机的二叉搜索树,就和随机的快排是一样的了。
首先随机打乱数组的序列,然后调用BST排序。
然后随机化的快排和随机化的BST做的就是相同的比较了,所以它们的复杂度是一样的,都是nlogn。

一棵随机化的二叉搜索树,高度的期望值是logn。

平衡搜索树

平衡搜索树(Balanced Search Tree)是这样的一种数据结构,它维护一个n个元素的动态集,复杂度是logn阶的,所以树高为O(logn)。平衡搜索树不一定是二叉树。

平衡搜索树主要有以下几种:

  • AVL树(二叉的)
  • 2-3树
  • 2-3-4树
  • B树
  • 红黑树(二叉的)
  • 跳跃表(不是树,但多少有一些树的结构)
  • 树堆

这里主要讲红黑树

红黑树

性质

红黑树是一种平衡搜索树,它能保证树高是logn级的,所有的操作都能在logn的时间完成。红黑树也是二叉搜索树的一种。红黑树每个节点都有一个色域,满足红黑性,有4个性质:

  1. 每个节点要么是红色,要么是黑色
  2. 根节点和叶节点(nil)都是黑色的。叶节点是最后的内部节点的空指针,这样每个内部节点都有两个子节点,每个叶子节点有0个子节点。
    在这里插入图片描述
  3. 每个红色节点的父节点都是黑色的。也就是说,如果观察树的任意路径,不可能找到两个连续的红色节点,只能找到红黑相间的或者是几个连续的黑节点,也可以得出,最多只有一半的节点是红色的。
    在这里插入图片描述
  4. 如果选择一条简单路径(不重复任何节点),从一个节点x一直到x的子孙叶节点,所有到各子孙叶节点的路径都有相等的黑节点数。也就是所有路径的“黑高度”都是相等的。计算“黑高度”时不包括x本身。
    在这里插入图片描述

举例:
看看下面这棵红黑树每个节点的黑高度是多少。所有的叶节点黑高度都是0,其它节点的黑高度都标在图上了。
在这里插入图片描述
创建一棵红黑树并不难,最简单的可以一开始创建一个所有节点都是黑色的平衡二叉树。问题当插入和删除之后如何保持红黑性。

首先要证明这些性质能推导出树高为O(logn)的结论。

定理:有n个键的红黑树的高度h≤2log(n+1),也就是O(logn)。(只计算内部节点)

证明:
首先要将树做一个改造,把每个红节点跟它的父节点合并起来,变成下面这个图:
在这里插入图片描述
每个内部节点都有2~4个子节点,并且每个叶节点的深度一致,都等于根节点的黑高度。

假设原树的高度是h,改造后的树高度是h’,键数为n。
那么这棵树有n+1个叶节点(一棵平衡二叉树的叶节点树等于内部节点数+1),一棵2-3-4树的叶节点数 2h’≤ #leaves ≤4h’,因此 2h’ ≤ n+1,h’ ≤ log(n+1),叶节点数越多,高度会降低。
之前我们知道,一条路径上的红节点数最多是路径长的一半,所有路径里最长的就是树的高度,所以h’至少是h的一半,h’ ≥ 1/2·h,即h ≤ 2h’,因此h≤2log(n+1)。

红黑树上的操作

对于查询:
只要红黑树的树高是O(logn),那么红黑树的查询时间就是O(logn)。
对于插入和删除:
为了保持树的红黑性,有三种操作:

  1. BST操作
  2. 改变新节点颜色,并且为周边的节点重新着色
  3. 节点重新排列,改变指针(via rotations)

Rotation:
下图画的是树的一部分,三角形表示子树,圆形表示节点。

下面这个例子,从左往右是右旋B,右旋就是把节点A和B之间的这条边旋转90度,B的父节点变成了A的父节点,A变成B的新的父节点,子树也重新排序,α还是A的子树,γ还是B的子树,而β由A的子树变成了B的子树。
同理,从右往左就是左旋A。
在这里插入图片描述
这个操作保持了二叉搜索树的性质,即节点左子树的值都小于等于该节点,右子树的值都大于等于该节点。

旋转操作只花费常数级的时间,因为指针的改变是常数级的。

RB_Insert(X)
在红黑树中插入一个节点X。
基本思路:

  • 在BST中插入一个节点X,Tree_Insert(X)
  • 给这个节点定为红色。这样可以满足性质4,但如果它的父节点是红色,就不满足性质3 。
  • 如何弥补性质3?把对性质3的破坏往上移。从节点X开始往根节点重新着色,直到某个点再改用旋转来弥补,可能还需要重新着色。

举例:
还是对上面的红黑树,插入15 。15应该在11度右节点的位置。如下图所示:
在这里插入图片描述
但违反了性质3,现在从根节点到叶的一条路径上出现了两个连续的红节点。于是需要重新着色。如下图所示,节点10变成红色,8和11变成黑色。如下图:
在这里插入图片描述
现在,10和18不满足性质3了。不能再重新着色了,不能让3变红,7变黑,因为根节点必须是黑色。因此我们进行旋转。把18右旋转,如下图:
在这里插入图片描述
现在这棵树不平衡了,还需要旋转。左旋7,10变为根节点。根节点必须是黑色,所以10变成黑色,7要变成红色,如下图:
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章