红黑树

平衡树:
  1. AVL 树
  2. 2-3 树
  3. 2-3-4 树
  4. 红黑树
  5. 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           
  • 应用
 (参看《算法导论》)
posted @ 2021-08-09 21:10  萌新的学习之路  阅读(91)  评论(0编辑  收藏  举报