红黑树
平衡树:
- 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
-
应用
(参看《算法导论》)