• 算法导论笔记: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)

  • 相关阅读:
    变量和基本数据类型,深浅拷贝问题
    计算机系统与编程语言分类
    关于计算机硬件的基本知识
    Python学习之路——函数
    Python学习之路——Day06 元组
    day--07
    数据类型——可变不可变类型
    数字类型
    流程控制——while循环
    流程控制——if判断
  • 原文地址:https://www.cnblogs.com/gqtcgq/p/7247232.html
Copyright © 2020-2023  润新知