紅黑樹(刪除)

本文地址:http://blog.csdn.net/spch2008/article/details/9338923


相對於紅黑樹插入操作,刪除操作複雜的多。

第一:先看最簡單情況,即刪除紅色節點。刪除紅色節點,不影響紅黑樹平衡性質,如圖:

 

只需要刪除紅色節點,不需要進行調整,因爲不影響紅黑樹的性質。  黑色節點沒有增多也沒有減少。

注意:以下幾種單支情況在平衡的紅黑樹中不可能出現。


因爲上述的情況,紅黑樹處於不平衡狀態。(破壞到null,黑色節點數目相同)

所以,平衡狀態下紅黑樹要麼單支黑-紅,要麼有兩個子節點。


第二:刪除單支黑節點

        

此種情況被包含在“第三”中,詳見“第三”分析


第三:若刪除節點有左右兩個兒子,即左右子樹,需要按照二叉搜索樹的刪除規律,從右子樹中找最小的替換刪除節點(該節點至多有一個右子樹,

無左子樹),我們將該節點記爲y, 將刪除節點記爲z,將y的右兒子記爲x(可能爲空)。


刪除規則:用y替換z,交換y與z顏色,同時y = z,改變y的指向,讓y指向最終刪除節點。

爲了便於理解,可以先這樣假設:將y與z的數據交換,但顏色不交換,這樣,實際相當於將刪除轉移到了y節點,而z處保持原先狀態(處於平衡)。

此時可以完全不用了理會z節點,直接刪除y節點即可。因爲y最多隻有一個右子樹,無左子樹,這便轉移到了“第二”。


對於刪除y節點,有幾種考慮。

  1. 若y爲紅色,則這種情況如上述”第一“所述,並不影響平衡性。(null視爲黑色)

  2. 若y爲黑色,則刪除y後,x替換了y的位置,這樣x子樹相對於兄弟節點w爲根的子樹少了一個黑節點,影響平衡,需要進行調整。

 

     剩下的調整工作就是將x子樹中找一合適紅色節點,將其置黑,使得x子樹與w子樹達到平衡。

     若x爲紅色,直接將x置爲黑色,即可達到平衡;

   

      若x爲黑色,則分下列幾種情況。

     

      情況1:x的兄弟w爲紅色,則w的兒子必然全黑,w父親p也爲黑。

     

       改變p與w的顏色,同時對p做一次左旋,這樣就將情況1轉變爲情況2,3,4的一種。


      情況2:x的兄弟w爲黑色,x與w的父親顏色可紅可黑。

      

       因爲x子樹相對於其兄弟w子樹少一個黑色節點,可以將w置爲紅色,這樣,x子樹與w子樹黑色節點一致,保持了平衡。

      new x爲x與w的父親。new x相對於它的兄弟節點new w少一個黑色節點。如果new x爲紅色,則將new x置爲黑,則整棵樹平衡。否則,

      情況2轉換爲情況1,3,4  情況2轉變爲情況1,2,3,4.


      情況3:w爲黑色,w左孩子紅色,右孩子黑色。

     

       交換w與左孩子的顏色,對w進行右旋。轉換爲情況4


       情況4:w爲黑色,右孩子爲紅色。

      

        交換w與父親p顏色,同時對p做左旋。這樣左邊缺失的黑色就補回來了,同時,將w的右兒子置黑,這樣左右都達到平衡。


       個人認爲這四種狀況比較難以理解,總結了一下。情況2是最好理解的,減少右子樹的一個黑色節點,使x與w平衡,將不平衡點上移至x與w的父親。

       進行下一輪迭代。情況1:如果w爲紅色,通過旋轉,轉成成情況1,2,3進行處理。而情況3轉換爲情況4進行處理。也就是說,情況4是最接近最終解

       的情況。情況4:右兒子是紅色節點,那麼將缺失的黑色交給右兒子,通過旋轉,達到平衡。


       看一下STL的紅黑樹刪除調整操作 

  1. if (y->color != __rb_tree_red) {   
  2.     while (x != root && (x == 0 || x->color == __rb_tree_black))  
  3.       if (x == x_parent->left) {  
  4.         __rb_tree_node_base* w = x_parent->right;  
  5.         //情況1  
  6.         if (w->color == __rb_tree_red) {  
  7.           w->color = __rb_tree_black;  
  8.           x_parent->color = __rb_tree_red;  
  9.           __rb_tree_rotate_left(x_parent, root);  
  10.           w = x_parent->right;  
  11.         }  
  12.         //情況2  
  13.         if ((w->left == 0 || w->left->color == __rb_tree_black) &&  
  14.             (w->right == 0 || w->right->color == __rb_tree_black)) {  
  15.           w->color = __rb_tree_red;  
  16.           x = x_parent;  
  17.           x_parent = x_parent->parent;  
  18.         }   
  19.         else   
  20.         {  
  21.           //情況3  
  22.           if (w->right == 0 || w->right->color == __rb_tree_black) {  
  23.             if (w->left) w->left->color = __rb_tree_black;  
  24.             w->color = __rb_tree_red;  
  25.             __rb_tree_rotate_right(w, root);  
  26.             w = x_parent->right;  
  27.           }  
  28.           //情況4  
  29.           w->color = x_parent->color;  
  30.           x_parent->color = __rb_tree_black;  
  31.           if (w->right) w->right->color = __rb_tree_black;  
  32.           __rb_tree_rotate_left(x_parent, root);  
  33.           break;  
  34.         }  
  35.       }  
  36.       if (x) x->color = __rb_tree_black;  
  37.     }  
只截取了平衡調整部分的代碼,且省略在右側刪除的情況。
發佈了104 篇原創文章 · 獲贊 229 · 訪問量 31萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章