zoukankan      html  css  js  c++  java
  • 算法导论笔记:13-03红黑树删除

           红黑树的删除操作花费O(lg n)时间,删除算法与二叉搜索树的删除类似,首先红黑树的TRANSPLANT版本有些许不同,主要是因为红黑树使用nil结点代替NULL指针造成的:

    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.p = u.p

     

    删除操作的代码如下:

    RB-DELETE(T.z)                    

           y = z                             

           y-original-color = y.color        

           if z.left == T.nil                

                  x = z.right                       

                  RB-TRANSPLAN(T, z, z.right)

     

           else if z.right == T.nil           

                  x = z.left                        

                  RB-TRANSPLAN(T, z, z.left)    

     

           else y = TREE-MINIMUM(z.right)    

                 y-original-color= y.color       

                 x= y.right                      

                 if y.p == z                      

                        x.p= y                           

                 else RB-TRANSPLANT(T, y, y.right)    

                        y.right= z.right                

                        y.right.p= y                    

                 RB-TRANSPLANT(T,z, y)           

                 y.left = z.left                  

                 y.left.p= y                     

                 y.color= z.color     

              

          if y-original-color == BLACK     

                 RB-DELETE-FIXUP(T.x)     

          

    调整代码如下:

           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                                                

                                       w.color =BLACK                              // case 1                                       

                                       x.p.color =RED                               // case 1                                       

                                       LEFT-ROTATE(T,x.p)                        // case 1                                   

                                       w = x.p.right                                   // case1 

                                           

                                if w.left.color ==BLACK and w.right.color == BLACK             

                                      w.color= RED                                 //case 2                                        

                                      x= x.p                                             //case 2      

                                           

                               else if w.right.color == BLACK                                 

                                             w.left.color = BLACK                       // case 4                                 

                                             w.color = RED                                 // case 4                                         

                                             RIGHT-ROTATE(T,w)                        // case 4                                    

                                             w = x.p.right                                   // case 4   

                                        

                                       w.color = x.p.color                                 // case 3                                  

                                      x.p.color = BLACK                                  // case 3                                    

                                      w.right.color = BLACK                                   // case 3                                

                                      LEFT-ROTATE(T, x.p)                               // case 3                                  

                                      x = T.root                                               // case 3    

                                           

                 else(same as then clause with “right” and “left” exchanged)

     ......

          x.color= BLACK      

                                             

           根据代码,可以将删除操作分为四种情况(等同于二叉搜索树的删除),代码中的x, y, z的意思如下:

           z表示要删除的元素;

           y表示实际要删除的元素,对于前两种情况(z只有一个孩子),y就是z;对于后两种情况(z有俩孩子),yz的后继元素。

           x表示删除y之后,代替y所在位置的元素。

    具体情况如下图, :

           情况一,二很简单,不再赘述,对于情况三和四,表面上看好像是删除了结点z,实际上是删除了结点y,因为在结点z的位置上,下面的代码保证了:除了z.key变成了y.key,其他的属性left, right, p, color都没有发生实质的变化。    所以,在红黑树中,实际上是删除了结点y,而结点x则成为在y所在位置的新节点。

           y.right = z.right                

           y.right.p= y

           RB-TRANSPLANT(T, z, y)           

           y.left= z.left                  

           y.left.p= y                     

           y.color= z.color

     

           得出上面的结论后,就看下删除y结点之后,给红黑树的性质带来了哪些变化:

           如果y的颜色是RED,则y不可能为红黑树的根,所以不管x的颜色是什么,都不会影响到红黑树的性质。所以只考虑y的颜色为BLACK的情况。

     

           y的颜色是BLACK的情况下,如果x的颜色为RED的话,删除y之后,结点y所在的分支的黑高就会减1,所以,只需要将x的颜色变为BLACK,则该分支的黑高会加1,则会保持住红黑树的颜色性质。

     

           所以最终要考虑的情况就是,y颜色为BLACKx的颜色为BLACK的情况。因把y删除后,x顶替y的位置,y所在分支的黑高减1,所以,假设x节点的颜色为BLACK-BLACK,简称BB,也就是原来y的BLACK增加到x上了,这样就保证了该分支的黑高不变,接下来要做的就是调整x所在的分支,使红黑树的性质保持不变,又分为下面的几种情况(只考虑x为左孩子的情况,右孩子的情况是对称的)

     

           对于下面四种情况之间的转换,需要保证转换前和转换后,红黑树的性质都得到了维持。

     

    1:x的兄弟结点w的颜色为RED,记为case1。

           因为w为RED,所以x.p的颜色为BLACK,w的两个孩子的颜色都为BLACK,如下图:

           转换前,满足下面的性质:

    abh(p) =bh(x) + 2 = bh(w) = bh(1) + 1 = bh(2) + 1

    b:整个分支的黑高为bh(p)+ 1 (p.color == BLACK) = bh(x) + 3

     

           对于这种情况,需要做的调整的代码如下:

                                       w.color =BLACK                              // case1                                       

                                       x.p.color =RED                               // case1                                       

                                       LEFT-ROTATE(T,x.p)                        // case 1                                   

                                       w = x.p.right                                   // case1 

     

           经过w.color = BLACK和x.p.color = RED的调整后,如下图:

    对结点p进行左旋:LEFT-ROTATE(T, x.p),左旋之后,得到下面的图:

           调整后,满足下面的性质:

    abh(x),  bh(1), bh(2)的值保持不变

    b:因调整前有:bh(x)+ 2 = bh(1) + 1 = bh(2) + 1

           所以,bh(p) = bh(x) + 2 = bh(1) + 1,所以p结点为根的子树满足红黑树性质;                  

    bh(w) = bh(2) + 1 = bh(p)所以w结点为根的子树满足红黑树性质

     

    c:整个分支的黑高为bh(w)+ 1 (w.color == BLACK) = bh(x) + 3,所以,整个分支的黑高没变

     

           这时,x的兄弟的颜色为BLACK,所以经过w = x.p.right后,得到了另外一种情况;

           这种情况下,要根据w的孩子结点的颜色不同分为三种情况:

     

    2:首先是w的孩子的颜色都是BLACK的情况下,记为case2:

           转换前,满足下面的性质:

    abh(p) =bh(x) + 2 = bh(1) + 2 = bh(2) + 2 = bh(w)+1

     

    b:整个分支的黑高为bh(p)+ 1/0(p.color == BLACK?1:0) = bh(x) + 3/2(p.color == BLACK?3:2)

     

    对于这种情况,需要调整的代码为:

                                      w.color = RED                               // case 2                                        

                                      x= x.p                                             //case 2 

     

    调整后,得到下面的图:

           调整后,满足下面的性质:

    abh(x),  bh(1), bh(2)的值保持不变

    b:因调整前有:bh(x)+ 2 = bh(1) + 2 = bh(2) + 2

           所以,bh( )= bh(x) + 1 = bh(1) + 1 = bh(2) + 1 结点为根的子树满足红黑树性质; bh(w) = bh(1) + 1 = bh(2) + 1 w结点为根的子树满足红黑树性质

     

           如果p,也就是 的颜色为RED,则退出循环,并且置 颜色为BLACK。

    c:整个分支的黑高为bh( )+ 1 ( .color== BLACK) = bh(x) + 2,所以,整个分支的黑高没变。

     

           如果p的颜色为BLACK,则 的颜色为BLACK-BLACK。

    c:整个分支的黑高为bh( )+ 2 ( .color== BB) = bh(x) + 3,所以,整个分支的黑高没变。

     

    这样, 之下的结点维持了红黑树的性质,然后以 为新的结点继续循环处理。

     

    3:如果w的右孩子结点为RED,左节点颜色为任意,case3:

           转换前,满足下面的性质:

    abh(p) =bh(x) + 2 = bh(2) + 1 = bh(1) + 2/1(1.color == BLACK?2:1)

     

    b:整个分支的黑高为bh(p)+ 1/0(p.color == BLACK?1:0) = bh(x) + 3/2(p.color == BLACK?3:2)

     

    对于这种情况,需要调整的代码为:

                               w.color = x.p.color                                 // case 3                                  

                               x.p.color= BLACK                                  //case 3                                    

                               w.right.color= BLACK                            //case 3                                

                               LEFT-ROTATE(T,x.p)                          // case3                                  

                               x = T.root                                               //case 3 

     

           经过w.color = x.p.color; x.p.color = BLACK;w.right.color = BLACK之后,得到下面的图:

    经过LEFT-ROTATE(T, x.p)和x = T.root之后,得到下图:

           调整后,满足下面的性质:

    abh(x),  bh(1), bh(2)的值保持不变

    b:因调整前有:bh(x)+ 2 = bh(2) + 1 = bh(1) + 2/1(1.color == BLACK?2:1)

           所以,bh(w) = bh(x) + 2 = bh(2) + 1 = bh(1) +2/1(1.color == BLACK?2:1)w结点为根的子树满足红黑树性质; bh(p) = bh(x) + 1 = bh(1) + 1/0(1.color == BLACK?1:0) w结点为根的子树满足红黑树性质

     

    c:整个分支的黑高为bh(w) + 1/0(p.color == BLACK?1:0)= bh(x) = 3/2(p.color == BLACK?3:2)。所以整个分支的黑高没变。

     

    4:如果w的右孩子结点为BLACK,左节点颜色为RED,case4:

           转换前,满足下面的性质:

    abh(p) =bh(x) + 2 = bh(2) + 2 = bh(1) + 1 = bh(3) + 2 = bh(4) + 2

     

    b:整个分支的黑高为bh(p)+ 1/0(p.color == BLACK?1:0) = bh(x) +3/2(p.color == BLACK?3:2)

     

    对于这种情况,需要调整的代码为:

                                      w.left.color= BLACK                       // case 4                                 

                                      w.color= RED                                 //case 4                                        

                                      RIGHT-ROTATE(T,w)                   // case 4                                    

                                      w= x.p.right                                   //case 4   

     

    经过w.left.color = BLACK和w.color = RED的调整后,得到下面的图:

    经过RIGHT-ROTATE(T.w)和w = x.p.right的调整之后,得到下面的图:

    调整后,满足下面的性质:

    abh(x),  bh(3), bh(4),  bh(2)的值保持不变

    b:因调整前有bh(x)+ 2 = bh(2) + 2 = bh(3) + 2 = bh(4) + 2所以:

           bh(w)= bh(4) + 1 = b(2) + 1,所以,w为根节点的子树红黑树性质没变;

           bh( )= bh(3) + 1 = bh(4) + 1 = b(2) + 1,所以, 为根节点的子树红黑树性质没变;

           bh(p)= bh(x) +2 = bh(3) + 2 = bh(4) + 2 = b(2) + 2,所以,p为根节点的子树红黑树性质没变;

     

    c:整个分支的黑高为bh(p)+ 1/0(p.color == BLACK?1:0) = bh(x) +3/2(p.color == BLACK?3:2),所以整个分支的黑高。

     

    同时注意到,新的w( )颜色为BLACK,而其右孩子为RED,符合case3。


    分析:

           n个结点的红黑树高度为O(lg n),不调用RB-DELETE-FIXUP时,时间代价为O(lg n),情况1可以转换为情况2;也可以转换为情况3,然后退出循环;也可以转换为情况4,然后情况4可以转换为情况3,情况3只执行一次循环。情况2是唯一能在while循环中执行多次的情况,所以RB-DELETE-FIXUP的时间复杂度为O(lg n)。所以,红黑树的删除的时间复杂度为O(lg n)

  • 相关阅读:
    14_java之变量|参数|返回值|修饰符
    NYOJ 202 红黑树 (二叉树)
    NYOJ 138 找球号(二) (哈希)
    NYOJ 136 等式 (哈希)
    NYOJ 133 子序列 (离散化)
    NYOJ 129 树的判定 (并查集)
    NYOJ 117 求逆序数 (树状数组)
    NYOJ 93 汉诺塔 (数学)
    HDU 2050 折线分割平面 (数学)
    天梯赛L2-008 最长对称子串 (字符串处理)
  • 原文地址:https://www.cnblogs.com/gqtcgq/p/7247232.html
Copyright © 2011-2022 走看看