红黑树
平衡树:
- AVL 树
- 2-3 树
- 2-3-4 树
- 红黑树
- B-树
红黑树的性质:
1.每个结点要么是黑色或者红色。
2.根结点和叶节点(nil)是黑色。
3.如果一个结点是红色的,则它的父结点和两个子结点都是黑色的。
4.对每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点,称为黑高。bh(x)
推论:
1.一棵有n个结点的红黑树高度至多为2lg(n + 1)。
-
插入操作
关键:使用recolor 和 rotation 操作维持RBT的红黑属性。
1. case1: x的叔结点y是红色的。
2. case2: x的叔结点y是黑色的且x是一个右孩子。
3. case3: x的叔结点y是黑色的且x是一个左孩子。
一次插入操作时间复杂度:O(lgn)
RB-Insert(T, z):
y = T.nil. // 二叉搜索树的插入操作
x = T.root
while x != T.nil:
y = x
if z.key < x.key:
x = x.left
else:
x = x.right
z.p = y
if y == T.nil:
T.root = z
else if z.key < y.key:
y.left = z
else:
y.right = z
z.left = T.nil
z.right = T.nil
z.color = RED
RB-INSERT-FIXUP(T, z)
RB-INSERT-FIXUP(T, z):
while z != T.root and z.p.color == RED:
if z.p == z.p.p.left:
y = z.p.p.right
if y.color = RED: // case1: 将 z 祖父结点的Black属性下移给其子节点
z.p.color = BLACK // 因为 z.p 和 y 都是Red属性,所以对称转移不会改变RBT的属性
y.color = BLACK
z.p.p.color = RED
z = z.p.p
else if z == z.p.right: // case2: z 是右子结点,对x父结点左旋将 z 和 z.p 放在一条直线上
z = z.p
LEFT_ROTATION(T, z)
z.p.color = BLACK // case3: 可能由case2转移得到,先重新着色,再对 z 祖父结点右旋将 z 的父结点作为新子树的根结点
z.p.p.color = RED
RIGHT_ROTATION(T, z.p.p)
else: // 对称如果 z 父结点是右子树结点,有3种case
// same as above with “right” and “left” exchanged
T.root.color = BLACK
-
删除操作
恢复红黑树属性。
1. case1: x 的兄弟结点 w 是红色的。
2. case2: x 的兄弟结点 w 是黑色的,而且 w 的两个子结点都是黑色的。
3. case3: x 的兄弟结点 w 是黑色的,w 的左子结点是红色的,右子结点是黑色的。
4. case4: x 的兄弟结点 w 是黑色的,w 的右子结点是红色的。
一次删除操作时间复杂度:O(lgn)
RB-TRANSPLANT(T, u, v): // 用子树 v 代替 u
if u.p == T.nil:
T.root = v
else if u == u.p.left:
u.p.left = v
else:
u.p.right = v
v.p = u.p
RB- DELETE(T, z):
y = z
y_original_color = y.color
if z.left = T.nil: // case1: 被删除结点只有右子结点
x = z.right
RB-TRANSPLANT(T, y, x) // 将 x 移到 y 的原始位置
else if z.right = T.nil: // case2: 被删除结点只有左子结点
x = z.left
RB-TRANSPLANT(T, y, x)
else: // case3: 被删除结点有左右子结点
y = TREE-MINIMUM(z.right) // 找到后继结点 y
y_original_color = y.color
x = y.right
if y.p == z: // 其他情况:x.p = y.p
x.p = y
else:
RB-TRANSPLANT(T, y, x) // 将 x 移到 y 的原始位置
y.right = z.right // 原 z 的左右子结点要转移成 y 的左右子结点
y.right.p = y
RB-TRANSPLANT(T, z, y) // 将 y 移到 z 的原始位置
y.left = z.left // 原 z 的左右子结点要转移成 y 的左右子结点
y.left.p = y
y.color = z
if y-original-color == BLACK: // 如果删除/移动的是红色结点不影响RBT树的红黑属性
RB-DELETE-FIXUP(T, x) // 否则要维护树的红黑属性
/*
如果 y.color是黑色,则上述删除操作可能造成3个问题:
1.如果 y 是原来的根结点,而 y 的一个红色孩子成为新的根结点,违反性质2.
2.如果 x 和 x.p (原 y.p)都是红色,违反性质3.
3.在树中移动 y 结点将导致先前包含 y (之后不包含)的任何简单路径上黑结点个数少1,因此 y 的任何子线不满足性质4.
改正这一问题的办法是:将现在占有 y 原来位置的结点 x 视为还有一重额外的黑色。即:如果将任意包含结点 x 的简单路径上黑结点个数加1,则在这种假设下,性质4成立。当黑结点 y 删除或移动时,将其黑色属性“下推”给 x。现在的 x 是双重黑色或者红黑色,分别给包含 x 的简单路径上黑结点数贡献2或1。x 的color属性仍然是RED(如果 x 是红黑色的)或者BLACK(如果 x 是双重黑色的)。换而言之,结点额外的黑色是针对 x 结点的,而不是反映在它的color属性上。
*/
RB-DELETE-FIXUP(T, x):
while x != T.root and x.color == BLACK:
if x == x.p.left:
w = x.p.right
if w.color == RED: // case1: 将 x 父结点左旋,转移到case2
w.color = BLACK
x.p.color = RED
LEFT-ROTATION(T, x.p)
w = x.p.right
if w.left.color == BLACK and w.right.color == BLACK: // case2
w.color = RED
x = x.p
else if w.right.color == BLACK: // case3
w.left.color = BLACK
w.color = RED
RIHGT-ROTATION(T, w)
w = x.p.right
w.color = x.p.color // case4
x.p.color = BLACK
w.right.color = BLACK
LEFT-ROTATION(T, x.p)
x = T.root
else:
// same as above with “right” and “left” exchanged
x.color = BLACK
-
应用
(参看《算法导论》)

浙公网安备 33010602011771号