紅黑樹(二):刪除

  紅黑樹的刪除操做,較之插入更爲複雜,由於紅黑樹也是二叉搜索樹,因此紅黑樹的刪除流程跟二叉搜索樹同樣,先找到要刪除的目標節點T,若是T沒有子節點,則將T直接刪除,若是T有一個子節點,則將此子節點替換到T的位置,而後刪除T,不然若是有兩個子節點,則在T的子樹中尋找後繼節點X,而後將X的值覆蓋到T結點,而後刪除此後繼節點X。後繼節點有兩種,一是在T的左子樹中找值最大的節點,此節點最多隻有一個左子節點,二是在T的右子樹中尋找T的最小值的節點,此節點最多隻有一個右子節點,兩種後繼節點選擇其一均可以。將後繼節點刪除後,不論是刪除的目標節點T,仍是刪除的是後繼節點X,最後都有一個節點會頂替被刪除節點的位置,設爲N,刪除後還須要對N進行顏色的修正。node

  這裏,咱們只須要討論刪除後繼節點X的狀況,由於直接刪除目標節點T時,表示目標節點T沒有任何子節點,很是簡單,並且已經包含在刪除後繼節點X的狀況中。spa

  在深刻討論前,先作一些約定,設待刪除節點(後繼節點)爲X,刪除後繼節點後,代替後繼節點位置的節點是NX的父節點,也就是如今N節點的父節點爲PN的祖父節點爲GN的叔節點爲UU的左子節點爲L, 右子節點爲爲R,以下圖所示:code

   

(以上只做爲各節點命名說明,各節點顏色並未標出,N便可爲左子節點,也能夠是右子節點,看你選擇是的哪一種後繼節點,並且N是能夠有一個子節點的,並未畫出。)blog

  像上一篇紅黑樹插入操做討論的同樣,紅黑樹的刪除操做有可能破壞紅黑樹的哪些性質(紅黑樹的五個性質不熟悉請參考紅黑樹(一):插入)呢?性質123確定不會被破壞,性質4也不會破壞,那只有可能破壞性質5,操做一個節點固然可能致使某節點的黑高改變了,這時候就須要針對性質5作修正。class

  首先,若是待刪除節點X顏色爲紅點,則直接拿N替換X便可,由於X爲紅色,因此全部通過X的路徑黑高都不受影響,故無需作顏色修正操做,刪除完成。搜索

若是X的顏色爲黑色,則此時全部通過X的路徑的黑高都減少了1,這時候破壞了紅黑樹的性質5,若是X的子節點N顏色爲紅色,則直接將N顏色染成黑色,這樣頂替X後,通過N的路徑黑高仍然保持不變,故無需修正,而當N的顏色爲黑色時,則複雜不少,像紅黑樹的插入操做同樣,此處也能夠分幾種狀況來分別討論。im

  狀況一:G爲黑色,ULR都爲黑色總結

     

 

  這種狀況下,通過N的路徑黑高都減少了1,爲了將通過N的兄弟U的路徑黑高也減少1,直接將U變爲黑色,這樣在局部維持了紅黑樹的性質5,但這樣一來,通過G的全部路徑,其黑高都減少了1,因此這個時候要對G再做處理,也就是向上傳遞修正。命名

  狀況二:G爲紅色,U, LR都爲黑db

   

  這種狀況下,直接交換G,U的顏色,便可恢復性質5

  狀況三:U爲紅色,GLR都爲黑

   

  這種狀況下,通過G->N的路徑少了一個黑色節點,此時先將G左旋轉,而後交換GU顏色,這個時候,能過GN的路徑多了一個節點N,而其它節點的黑高都沒有變化,這個時候,能將GL顏色互換,以維持通過G->在刪除前的黑高嗎?沒有這麼簡單,由於咱們如今還不知道L節點的子節點是什麼顏色,若是是紅色,則不能簡單交換,如下咱們接着討論,討論LR的顏色便是接下來的狀況四和狀況五。

  狀況四:G結點顏色任意,U結點爲黑,R節點爲紅,L節點顏色任一

   

  這種狀況下,將G左旋轉,而後將UG顏色交換,並將R顏色標黑,這個時候,任一節點都維持了刪除前的黑高。好比對通過L的路徑,刪除前是GUL,刪除後是UGLUG顏色先後互換了,但並不影響L此路徑黑高。對R的路徑,刪除前是GUR,刪除後是UR,其黑高也沒有變。

狀況五:G節點顏色任意,U節點爲黑,L爲紅,R爲黑(R不討論紅是由於狀況四中已包含這種狀況)

   

  這種狀況下,將U左旋轉,而後交換LU的顏色,這時候能夠看出,問題已經轉化成狀況四了,按狀況四的處理流程便可。

狀況6:刪除後,N是新的根節點,這時候直接將N染成黑色便可。

  刪除總結:

    刪除的狀況看似多,但各類狀況並非雜亂無章。

    第一種狀況全黑,是最簡單的狀況,可是卻要向上傳遞修正。

    第二,三種狀況討論的是GU結點分別爲紅的狀況。同時第三種狀況引出了狀況四和五。

    第四和第五種狀況則討論了一個節點爲紅和兩節點均可能爲紅的狀況。

 1 RBTreeNode* RBTreeDelete(RBTreeNode* pRoot, int nData) {
 2     RBTreeNode* pToDelete = pRoot;
 3 
 4     while (pToDelete != RBTreeNilNodePtr) {
 5         if (nData > pToDelete->nData) {
 6             pToDelete = pToDelete->pRight;
 7         }
 8         else if (nData < pToDelete->nData) {
 9             pToDelete = pToDelete->pLeft;
10         }
11         else
12             break;
13     }
14     if (pToDelete == RBTreeNilNodePtr)
15         return pRoot;
16 
17     if (pToDelete->pLeft != RBTreeNilNodePtr && pToDelete->pRight != RBTreeNilNodePtr) {
18         //RBTreeNode* pMinNode = RBTreeMinimumNode(pToDelete->pRight);
19         RBTreeNode* pMaxNode = RBTreeMaximumNode(pToDelete->pLeft);
20         pToDelete->nData = pMaxNode->nData;
21         pToDelete = pMaxNode;
22     }
23     if (pToDelete->pLeft == RBTreeNilNodePtr || pToDelete->pRight == RBTreeNilNodePtr) {
24         RBTreeNode* pParent = pToDelete->pParent;
25         RBTreeNode* pTemp = (pToDelete->pLeft == RBTreeNilNodePtr) ? pToDelete->pRight : pToDelete->pLeft;
26         bool isRed = pToDelete->isRed;
27 
28         if (pParent != RBTreeNilNodePtr) {
29             if (pParent->pLeft == pToDelete)
30                 pParent->pLeft = pTemp;
31             else
32                 pParent->pRight = pTemp;
33         }
34 
35         if (pTemp != RBTreeNilNodePtr)
36             pTemp->pParent = pParent;
37 
38         if (!isRed) {
39             //刪除是的黑色節點
40             if (pToDelete == pRoot) {
41                 pRoot = pTemp;
42             }
43             if (pTemp != RBTreeNilNodePtr) {
44                 if (pTemp->isRed) {
45                     //刪除的是黑色節點時,把紅色子節點直接變成黑色
46                     pTemp->isRed = RBTreeNodeBlack;
47                 }
48                 else if (pParent != RBTreeNilNodePtr) {
49                     //刪除的是一個黑色結點
50                     FixRBTreenodeColor_Delete(&pRoot, pTemp, pTemp->pParent);
51                 }
52             }
53             else if (pParent != RBTreeNilNodePtr) {
54                 FixRBTreenodeColor_Delete(&pRoot, RBTreeNilNodePtr, pParent);
55             }
56         }
57     }
58     delete pToDelete;
59     return pRoot;
60 }
  1 void FixRBTreenodeColor_Delete(RBTreeNode** pRoot, RBTreeNode* pNode, RBTreeNode* pParent) {
  2     if (pParent == RBTreeNilNodePtr && pNode != RBTreeNilNodePtr) {
  3         pNode->isRed = RBTreeNodeBlack;
  4         return;
  5     }
  6     if (pNode->isRed)
  7         return;
  8 
  9     if (pNode == pParent->pLeft) {
 10         RBTreeNode* pBrother = pParent->pRight;
 11         //pBrother不可能爲空,不然通過pParent的節點黑高不平衡,pBrotherLeft和pBrotherRight多是RBTreeNilNodePtr
 12         RBTreeNode* pBrotherLeft = pBrother->pLeft;
 13         RBTreeNode* pBrotherRight = pBrother->pRight;
 14         if (!pBrother->isRed && !pParent->isRed) {
 15             if (!pBrotherLeft->isRed && !pBrotherRight->isRed) {
 16                 //狀況1:父節點爲黑,兄弟節點及其子節點都爲黑
 17                 pBrother->isRed = RBTreeNodeRed;
 18                 FixRBTreenodeColor_Delete(pRoot, pParent, pParent->pParent);
 19             }
 20         }
 21         else if(pBrother->isRed && !pParent->isRed){
 22             //狀況3:父節點爲黑,兄弟結點爲紅
 23             //先左旋轉父節點
 24             RBTreeNode* pGrandParent = RBTreeLeftRotate(pRoot, pParent);
 25 
 26             pParent = pGrandParent->pLeft;
 27             //再交換顏色 
 28             SwapRBTreeNodeColor(pGrandParent, pParent);
 29             pBrother = pParent->pRight;
 30         }
 31         if (pParent->isRed) {
 32             //pBrother必定是黑
 33             if (!pBrotherLeft->isRed && !pBrotherRight->isRed) {
 34                 //狀況2:父節點爲紅,交換pParent和pBrother的顏色
 35                 SwapRBTreeNodeColor(pParent, pBrother);
 36                 return;
 37             }
 38         }
 39         if (pBrotherLeft->isRed && !pBrotherRight->isRed) {
 40             //狀況5:兄弟節點的左子節點爲紅,此時轉化爲狀況4
 41             //將pBrother右旋轉
 42             pBrother = RBTreeRightRotate(pRoot, pBrother);
 43 
 44             pBrotherRight = pBrother->pRight;
 45 
 46             //交換顏色
 47             SwapRBTreeNodeColor(pBrother, pBrotherRight);
 48         }
 49         if (pBrotherRight->isRed) {
 50             //狀況4:先左旋轉pParent
 51             RBTreeNode* pGrandParent = RBTreeLeftRotate(pRoot, pParent);
 52             pParent = pGrandParent->pLeft;
 53 
 54             //交換顏色
 55             SwapRBTreeNodeColor(pGrandParent, pParent);
 56 
 57             //將pBrotherRight標黑
 58             pBrotherRight->isRed = RBTreeNodeBlack;
 59         }
 60     }
 61     else {
 62         RBTreeNode* pBrother = pParent->pLeft;
 63         //pBrother不可能爲空,不然通過pParent的節點黑高不平衡,pBrotherLeft和pBrotherRight多是RBTreeNilNodePtr
 64         RBTreeNode* pBrotherLeft = pBrother->pLeft;
 65         RBTreeNode* pBrotherRight = pBrother->pRight;
 66 
 67         if (!pBrother->isRed && !pParent->isRed) {
 68             if (!pBrotherLeft->isRed && !pBrotherRight->isRed) {
 69                 //狀況1:父節點爲黑,兄弟節點及其子節點都爲黑
 70                 pBrother->isRed = RBTreeNodeRed;
 71                 FixRBTreenodeColor_Delete(pRoot, pParent, pParent->pParent);
 72             }
 73         }
 74         else if (pBrother->isRed && !pParent->isRed) {
 75             //狀況3:父節點爲黑,兄弟結點爲紅
 76             //先左旋轉父節點
 77             RBTreeNode* pGrandParent = RBTreeRightRotate(pRoot, pParent);
 78 
 79             pParent = pGrandParent->pRight;
 80             //再交換顏色 
 81             SwapRBTreeNodeColor(pGrandParent, pParent);
 82             pBrother = pParent->pLeft;
 83         }
 84         if (pParent->isRed) {
 85             //pBrother必定是黑
 86             if (!pBrotherLeft->isRed && !pBrotherRight->isRed) {
 87                 //狀況2:父節點爲紅,交換pParent和pBrother的顏色
 88                 SwapRBTreeNodeColor(pParent, pBrother);
 89                 return;
 90             }
 91         }
 92         if (pBrotherRight->isRed && !pBrotherLeft->isRed) {
 93             //狀況5:兄弟節點的左子節點爲紅,右子節點爲黑, 此時轉化爲狀況4
 94             //將pBrother右旋轉
 95             pBrother = RBTreeLeftRotate(pRoot, pBrother);
 96 
 97             pBrotherLeft = pBrother->pLeft;
 98 
 99             //交換顏色
100             SwapRBTreeNodeColor(pBrother, pBrotherLeft);
101         }
102         if (pBrotherLeft->isRed) {
103             //狀況4:先左旋轉pParent
104             RBTreeNode* pGrandParent = RBTreeRightRotate(pRoot, pParent);
105             pParent = pGrandParent->pRight;
106 
107             //交換顏色
108             SwapRBTreeNodeColor(pGrandParent, pParent);
109 
110             //將pBrotherRight標黑
111             pBrotherLeft->isRed = RBTreeNodeBlack;
112         }
113     }
114 }
相關文章
相關標籤/搜索