紅黑樹之樹節點的刪除

上一個筆記記錄的是紅黑樹的建立,即紅黑樹的插入。今天來看看紅黑樹節點刪除!
首先,我們第一個問到的問題就是:刪除一個節點應該怎樣刪除?看下面的二叉查找樹:
當我們想刪除2這個節點時,會發現如果就簡單的給刪除,不知道是將1給連接到11後面還是將7連接到11的後面。當然可以將7連接上去,然後將1的做孩子連接到5節點,但是當1後面有左孩子時,我們是不是又要去找1爲根的子樹的最大值呢?而且將5連接上去那會不會造成樹的極度不平衡呢?其實不考慮效率,這是一種可以的方法的。爲了滿足樹的平衡性,我們一般是找2的後繼,即在此樹中4爲2的後繼。這樣,我們只要簡單的將4刪除就行了。對於節點有個孩子節點爲空或孩子節點都爲空,那麼我們只要簡單的處理就行了。
下面來看紅黑樹的刪除:
紅黑樹的刪除,一個比較麻煩的地方就是刪除一個黑節點後樹的紅黑性質得不到保持,從而要想辦法將這種性質保存下來。下面來看看,刪除一個黑節點後我們需要做什麼調整。
首先,看下圖
對於刪除17,我們會採用推到後繼節點的策略來進行刪除節點:首先將17的後繼節點19替換到17節點,當然此時紅黑性質保持不變,變的只是關鍵字,此時我們刪除下圖key所指的關鍵字17。
對於刪除後的圖爲:
此時關鍵字key指向的爲紅色節點爲20.這樣我們需要對20這個節點進行調整,因爲我們發現它違反了紅黑樹的規定。此時,我們直接將20給調整爲黑色就ok了。我們知道,刪除的節點肯定有一個孩子節點是空的,那麼當我們用孩子節點替換刪除的節點時,如果孩子節點爲紅色,我們直接調整這個孩子節點爲黑色就能夠保持紅黑樹的性質。那麼當我們刪除節點後孩子節點爲黑時,我們需要做哪些調整呢?且有多少種情況我們需要調整呢?
先來看刪除的節點在這個節點的父節點的左邊。
情況1:key節點的兄弟w節點爲黑色,w的兩個子節點爲黑色。
key所指的節點爲我們刪除後其孩子節點,即,節點已經刪除且爲黑色節點,而其孩子節點A替換上來後的圖。此時,我們要認識到B->A->...這條鏈上是少了一個黑色節點的,這樣有路徑只要包含這個路徑都會少一個黑色節點。如果我們將D變紅,那麼會違法第3條規則:紅色節點的子節點都爲黑色。但是我們可以將B變黑,這樣就保持了紅黑樹的性質。對這個圖我們是直接將B變黑就行了,但是對於下圖我們卻不能夠:
即key的父節點也爲黑,此時我們只要將B節點變爲key節點就行了,然後向上傳播循環處理。如果我們此時的B節點爲根節點那該怎麼辦呢?其實,這種情況是不會出現的。
情況2:
key節點的兄弟w節點爲黑色,w節點的右節點爲紅色。看似平衡了,其實你要想一想刪除的節點爲黑色節點,而替換的是黑色節點。即在B->A鏈路以後的鏈路中都會少一個黑色的節點。爲了平衡,我們可以將E變黑,B變黑 ,然後對B進行一個左旋轉;此時還應該考慮D節點的顏色:如果B爲紅,則D爲紅,如果B爲黑則D爲黑,即將B的顏色賦給D。


情況3:key節點的兄弟w節點爲黑色,w節點的左子節點爲紅色,右子節點爲黑色。
這種情況,讓w的左節點和w的顏色互換,然後對w進行右旋。這樣將情況轉換成了2.

情況4:key節點的兄弟節點w爲紅色。
這種情況下,key節點的兄弟節點w爲紅色。這種情況下父節點B可定是黑色,c,e節點也肯定是黑色。則可以,將B變成紅色,D變成黑色,然後對B進行左旋。
這樣就將情況4變成情況1,2,3中的一種了,再次循環就行了。

其實,樹節點的刪除是在刪除節點的父節點及其兄弟節點間進行調整。局部調整後就能夠將樹調整平衡。
下面是代碼,結合紅黑樹的建立,可以組成紅黑樹的建立及節點刪除。
 // delete.
int RBT_delete_fix(RBT* T,Node *x)
{
    if(T == NULL || (*T) == NULL || x == NULL)
    {
         return 0 ;
    }
 
    while(x != (*T) && x->color == BLACK)
    {
            if(x == x->parent->left) // x is parent left child.
            {
                 Node *parent = x->parent;
                 COLOR bc = BLACK ;
                 if(parent->right != NULL)
                 {
                     bc = parent->right->color ;
                 }
                 if(bc == RED)//case 4 brother is red.
                 {//the parent must be black.
                     parent->color = RED;
                     parent->right->color = BLACK ;
                     LEFT_ROATE(T,parent);
                 }else{//case 2 3 4 brother is black.  1 else
                        COLOR blc = BLACK ;
                        COLOR brc = BLACK ;
                        if(parent->right->left != NULL)
                        {
                              blc = parent->right->left->color ;
                        }
                        if(parent->right->right != NULL)
                        {
                             brc = parent->right->right->color ;
                        }
                        if(blc == BLACK && brc == BLACK)//CASE 1 
                        {
                            parent->right->color = RED;  
                            x = parent ;
                           
                        }else
                        {
                              if(blc == RED && brc == BLACK)// case 3
                             {
                              parent->right->color = RED ;
                              parent->right->left->color = BLACK ;
                              RIGHT_ROATE(T,parent->right);
                             }
                             //case 2 
                              parent->right->right->color = BLACK ;
                              parent->right->color = parent->color;
                              parent->color = BLACK ;
                              LEFT_ROATE(T,parent);
                              x = (*T); // break the while.
                        }
                       }// 1 else
            }else{// x is parent right child.
                 Node *parent = x->parent;
                 COLOR bc = BLACK ;
                 if(parent->left != NULL)
                 {
                     bc = parent->left->color ;
                 }
                 if(bc == RED)//case 4 brother is red.
                 {//the parent must be black.
                     parent->color = RED;
                     parent->left->color = BLACK ;
                     LEFT_ROATE(T,parent);
                 }else{//case 2 3 4 brother is black.  1 else
                        COLOR blc = BLACK ;
                        COLOR brc = BLACK ;
                        if(parent->left->left != NULL)
                        {
                              blc = parent->left->left->color ;
                        }
                        if(parent->left->right != NULL)
                        {
                             brc = parent->left->right->color ;
                        }
                        if(blc == BLACK && brc == BLACK)//CASE 1
                        {
                            parent->left->color = RED;  
                            x = parent ;
                           
                        }else
                        {
                              if(blc == BLACK && brc == RED)// case 3
                             {
                              parent->left->color = RED ;
                              parent->left->left->color = BLACK ;
                              LEFT_ROATE(T,parent->left);
                             }
                             //case 2
                              parent->left->right->color = BLACK ;
                              parent->left->color = parent->color;
                              parent->color = BLACK ;
                              RIGHT_ROATE(T,parent);
                              x = (*T); // break the while.
                        }
                       }// 1 else
                  }
    }//end while
    x->color = BLACK ;
}
Node * treeSuccessor(Node *x)
{
     if(x == NULL || x->right == NULL || x->left == NULL )
     {
             return NULL ;
     }
     Node *cur = x->right ;
     //x = cur ;
     while(cur != NULL)
     {
          x  = cur ;
         cur = cur->left ;
     }
     return x ;
 }
int RBT_delete(RBT *T,int key)
{
    if(T == NULL || (*T) == NULL )
    {
         return 0 ;// error .
    }
    Node *root = *T ;
    Node *cur  = root ;
    // find the key .
    while(cur != NULL)
    {
         if(cur->key == key)
         {
              break ;
         }
         if(cur->key > key )
         {
               cur = cur->left ;
         }else
         {
              cur = cur->right ;
          }
    }
    if(cur == NULL )
    {
         return 0 ;// not find key .
    }
    Node *y = cur ;
    if(cur->right != NULL && cur -> left != NULL)
    {// find the
         y = treeSuccessor(cur);
    }
    // 刪除
    if(y != cur )
    {
         cur->key = y->key ;//125489
    }
    Node *parent = y->parent ;
    Node *x      = NULL ;
    if(y->left != NULL)
    {
           x = y->left ;
    }else
    {
           x = y->right ;
    }
    if(x != NULL )
    {
        x->parent = parent ;
        if(parent != NULL)
        {
             if(y == parent->left)
             {
                  parent->left = x ;
             }else
             {
                  parent ->right = x ;
              }
        }else// y is root .
        {
                (*T) = x ;
         }
         if(y->color == BLACK)
         {
            RBT_delete_fix(T,x);
         }
         delete y ;
        
     }else
     {// x is null .
          x = new Node ;
          x->parent = parent ;
          x->color = BLACK ;
          if(parent == NULL)// root is only.
          {
             (*T) = NULL ;
             delete y ;
             delete x ;
             return 1 ;
          }
          if(y == parent->left)
          {
               parent ->left = x ;
          }else
          {
               parent->right = x ;
           }
           if(y ->color == BLACK)
           {
               RBT_delete_fix(T,x);
           }
           parent = x->parent ;
           if(x == parent->left)
           {
                parent->left = NULL ;
           }else
           {
                parent->right = NULL ;
            }
          delete y ;
          delete x ;
        
      }
   return 1 ;
}





發佈了31 篇原創文章 · 獲贊 9 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章