1.什么是红黑树
我们知道一棵高度为h的二叉搜索树的大部分操作时间复杂度是O(h),但是如果搜索树较高,极端情况下就是一条链表了,二叉搜索的意义就不大了。而红黑树是一颗二叉搜索树,也是多种平衡搜索树的一种,可以保证最坏情况下时间复杂度为O(lgn)。对于一棵有n个内部节点的红黑树的高度最多为2lg(n+1),高度的证明不难,请参考算法导论。
2.红黑树的五大性质
这五大性质非常重要,想要明白红黑树,这五个性质请大家必须牢记。一棵红黑树是满足下面红黑性质的二叉搜索树:
1. 每个节点或是红色的,或是黑色的
2. 根节点是黑色的
3.每个叶节点(NIL)是黑色的
4.如果一个节点是红色的,则它的两个子节点都是黑色的
5.对于每个几点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点。
关于性质一,第一眼看着好像就是废话没啥用,其实到了后面删除操作的时候就看出这个性质是很微妙的。这里还有两个概念,一个是哨兵节点,为了方便处理边界条件以及方便描述,我们把不需要关注的叶子节点和null节点统一用一个特殊节点表示,我们称它为哨兵节点,记为T.NIL。一个是黑高,从某个节点x出发(不含该节点)达到一个叶节点的任意一条简单路径上的黑色节点个数称为该节点的黑高。下面展示一棵普通的红黑树:
3.旋转操作
在红黑树进行新增节点或者删除节点的时候,有可能改变了红黑树的五大性质,所以我们需要对红黑树进行调整,左旋转(LEFT-ROTATE)和右旋转(RIGHT-ROTATE)是极其重要的两个操作。通过旋转和调整颜色可以恢复红黑树的五大性质。如下图所示,右旋转a节点会以a为中心,把它的左孩子b旋转为树根,然后把左孩子b的右孩子作为a的左孩子。右旋转则刚刚好相反。
下面展示左旋转伪代码(抄自算法导论,右旋转类似不列出)
// 以节点b为中心左旋转
LEFT-ROTATE(T, b)
a = b.right;
// 把右孩子a的左孩子给节点b做右孩子
b.right = a.left;
if a.left != T.NIL
a.left.p = b;
a.p = b.p;
if b.p == T.NIL
T.rooot = a;
else if b == b.p.left
b.p.left = a;
else b.p.right = a;
a.left = b;
b.p = a;
4.子树移植
红黑树的移植在删除中需要用到,被删除的节点的子树将要代替被删除的节点
//用以v为根的子树替代以U为根的子树
RB-TRANSPLANT(T, u, v):
if(u.p == T.NIL)
T.ROOT = v
else if u == u.p.left
u.p.left = v
else u.p.right = v
v.parent=u.parent
5.找出最小节点
红黑树删除的时候需要用到,如果被删除节点有双非空子树,找出该节点的后继节点TREE-MINIMUM(x)
while x.left != T.NIL
x = x.left;
return x;