红黑树(二):删除

  红黑树的删除操做,较之插入更为复杂,由于红黑树也是二叉搜索树,因此红黑树的删除流程跟二叉搜索树同样,先找到要删除的目标节点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 }
相关文章
相关标签/搜索