一、性质
- 每个结点要么是红的,要么是黑的
- 根结点是黑的
- 每个叶子节点(NIL节点,空节点)是黑色的;
- 如果某个子结点是红色,那么它的两个儿子都是黑色,且父节点也必定是黑色
- 对于任一结点而言,它到叶节点的每一条路径都包含相同数目的黑色结点
PS:NIL节点也称为外部节点或空节点,它是红黑树中一种特殊的节点类型。NIL节点不存储实际的数据,它们的作用是协助维护红黑树的结构和性质,同时也简化了一些操作的实现。
在红黑树中,每个节点要么是红色的,要么是黑色的,而每个节点都有左子节点和右子节点。NIL节点是所有叶子节点的虚拟父节点,它们都是黑色的,且不包含任何子节点。这意味着,如果一个节点没有左子节点或右子节点,那么它的对应子节点就是一个NIL节点。
通过将红黑树的所有叶子节点都替换为NIL节点,我们可以保证红黑树的每个节点都至少有一个子节点。这样,我们就可以通过判断节点的子节点是否为NIL节点来处理边界情况,避免了在处理节点时需要特殊处理叶子节点的情况。
在红黑树中,NIL节点通常用一个特殊的指针表示,比如用 NULL 或 nullptr 表示。在某些实现中,NIL节点可能会占用一些内存空间,但是由于它们不包含任何实际的数据,因此这种内存开销通常可以忽略不计。
二、插入标记
- 正在处理的结点X,也叫子节点
- 父节点称为P
- 爷爷结点称为G
- 叔叔结点称为Y
如下图所示:
其中
A
3
A_3
A3表示黑高为3的红黑树
三、插入调整
向红黑树插入节点时,新节点的颜色需要设置为红色。
3.1 无需调整的情况
- X为根节点,将X由红染黑,简称rootOver
- 父节点P为黑色,BlackParentOver,简称bpOver
3.2 仅需考虑父结点为红色的情形
由于性质4,爷爷结点G必定为黑色,分为三种情况:
- Y为红色,X可左可右:此时将P、Y染黑,G染红,X回溯至G
- Y为黑色,X为右孩子:左旋P,X指向P,转化为3
- Y为黑色,X为左孩子:P染黑,G染红,右旋G,结束
结论:红黑树的插入调整最多旋转两次
四、删除调整标记:
- 正在处理的节点为X
- 父节点为P
- 兄弟节点为S
- 左侄子leftNephew,简称LN
- 右侄子rightNephew,简称RN
五、删除调整
4.1 无需调整的情况
删除过程:
如果需要删除的节点为红色,那么无需调整
回溯过程:
- X为根节点,无论root什么颜色,都将root染黑
- X为红色,此时将X染黑(因为在执行这步前,删除了一个黑色节点BH(left)=BH(right-1),执行完这步,正好使得左子树和右子树的黑高相等,删除调整算法结束)
4.2 当X为P的左子树时,分为四种情况
Case1 S为红色:S染黑,P染红,左旋P
图解:
此时可以看到P仍是不平衡的,可以转化为:
- Case 2-2
- Case 3
- Case 4-1、Case 4-2
Case1不会引起BH的变化
Case2-1 S为黑色,LN为黑色,RN为黑色,P为黑色:将S染红,X回溯至P
处理方式为将S染红,X回溯至P
P为黑色的图解:
经过Case1的调整后:
- 符合性质4
- S的BH减少1,BH(X)==BH(S),所以P符和性质5
- P的BH减少了1,整个RBT违反性质5
- 需要继续调整P
Case2-1的转化情况
由于P是黑色,所以Case2-1可以转化为任意case
若P为根节点,则执行Case2-1会引起BH减少,这是唯一减少整个红黑树BH的情形。
Case2-2 其他条件相同 P为红色
P为红色的图解:
Case2-2的调整相同,也是将S染黑。
经过Case2-2调整后
- BH(S)减少了1,BH(X)==BH(S),所以符和性质5
- P的BH减少了1,此时整个RBT违反了性质5
- P与S的关系违反了性质4
调整策略:
直接将P染黑
Case 3 S为黑色,LN为红色,RN为黑色:将LN染黑,S染红,右旋S
‘经过Case 3调整后
- S的左右子树BH相等,所以S符和性质5
- LN的左右子树BH相等,所以LN符和性质5
- X的BH仍然比LN的BH少1,所以P违反性质5
- 需要继续调整X
Case 3的转化情况
- Case3可转化为Case4-1、Case4-2
- Case3不会引起BH的变化
Case 4-1 S为黑色,RN为红色,LN为红色:将S变为P的颜色,P和RN染黑,左旋P
LN为红色的图解:
处理方式:将S的颜色设置为与P相同,P染黑,RN染黑,左旋P,X指向根节点
Case4-2 与上面相同,但是LN为黑色
LN为黑色的图解:
调整过程与上面相同
经过Case 4的调整之后:
- 染黑之后的P正好填补了左子树缺少的一个BH
- RN染黑,正好填补了空缺的黑S,右子树的BH不变
- BH( P )==BH(RN),所以符和性质5
- 以S为根的子树BH和删除前一样,整个RBT平衡
- 没有任何违反性质4的节点
RBT的删除调整最多旋转3次
四、对比
4.1 AVL插入和RBT的插入
插入元素都是BST的插入,区别在于调整
旋转次数:AVL与RBT均是O(1)
指针回溯次数:最好情况
- AVL:很早就遇到单旋或双旋的情况,为O(1)
- RBT:很早就遇到2或3的情况,为O(1)
指针回溯次数,最坏情况
- 回溯至根结点才发现平衡因子大于1,为logN
- 不断执行1,直到根结点,但每次向上回溯两层。,为logN/2
插入效率:RBT略好于AVL
查询效率:AVL略好于RBT
4.2 AVL的删除和RBT的删除
删除节点都是BST的删除,区别在于调整
旋转次数:AVL与RBT均为O(1)
指针回溯次数,最好情况:
- AVL类似插入,可通过优化提前结束递归,为O(1)
- RBT也为O(1)
指针回溯次数,最坏情况:
- AVL回溯至根节点才发现平衡因子大于1,为logN
- RBT也为logN,但是RBT大部分形态下是红黑相间的,一直遇不到红色节点的情况很少见
删除效率:RBT略微好于AVL
4.3 查找
AVL树更加严格平衡,因此可以提供更快的查找效果。
4.3 在HashMap中为什么使用红黑树而不是AVL树
红黑树更通用,因为两者在添加、删除和查找等方面表现均相对较好,但AVL树的查找速度更快,代价是添加/删除速度较慢。