算法导论笔记: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所在位置的元素。

具体情况如下图, :

《算法导论笔记:13-03红黑树删除》

《算法导论笔记:13-03红黑树删除》

《算法导论笔记:13-03红黑树删除》

       情况一,二很简单,不再赘述,对于情况三和四,表面上看好像是删除了结点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,如下图:

《算法导论笔记:13-03红黑树删除》

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

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的调整后,如下图:

《算法导论笔记:13-03红黑树删除》

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

《算法导论笔记:13-03红黑树删除》

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

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后,得到了另外一种情况;

《算法导论笔记:13-03红黑树删除》

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

 

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

《算法导论笔记:13-03红黑树删除》

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

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 

 

调整后,得到下面的图:

《算法导论笔记:13-03红黑树删除》

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

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

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

       所以,bh( 《算法导论笔记:13-03红黑树删除》)= bh(x) + 1 = bh(1) + 1 = bh(2) + 1 结点为根的子树满足红黑树性质; bh(w) = bh(1) + 1 = bh(2) + 1 w结点为根的子树满足红黑树性质

 

       如果p,也就是 的颜色为RED,则退出循环,并且置 《算法导论笔记:13-03红黑树删除》颜色为BLACK。

c:整个分支的黑高为bh(《算法导论笔记:13-03红黑树删除》 )+ 1 ( 《算法导论笔记:13-03红黑树删除》.color== BLACK) = bh(x) + 2,所以,整个分支的黑高没变。

 

       如果p的颜色为BLACK,则 《算法导论笔记:13-03红黑树删除》的颜色为BLACK-BLACK。

c:整个分支的黑高为bh(《算法导论笔记:13-03红黑树删除》 )+ 2 ( .color== BB) = bh(x) + 3,所以,整个分支的黑高没变。

 

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

 

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

《算法导论笔记:13-03红黑树删除》

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

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之后,得到下面的图:

《算法导论笔记:13-03红黑树删除》

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

《算法导论笔记:13-03红黑树删除》

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

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:

《算法导论笔记:13-03红黑树删除》

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

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的调整后,得到下面的图:

《算法导论笔记:13-03红黑树删除》

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

《算法导论笔记:13-03红黑树删除》

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

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(《算法导论笔记:13-03红黑树删除》 )= 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(《算法导论笔记:13-03红黑树删除》 )颜色为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)

    原文作者:算法小白
    原文地址: https://blog.csdn.net/gqtcgq/article/details/45290427
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞