二叉平衡樹之刪除節點

二叉平衡樹之刪除節點操做

更好的判斷最小非平衡樹類型的方法

在前一篇文章中,咱們知道最小非平衡樹能夠分爲四種類型,即:LL型、LR型、RR型和RL型。並且我也按照本身的理解,概括了判斷是哪一種類型的方法。總結一下就是:設最小非平衡樹的樹根爲unbalance,首先看unbalance的左右子樹誰更高,若是左子樹更高則爲LX型、若是是右子樹高則爲RX型。再進一步,若是爲LX型,將剛剛插入的節點的值value與unbalance左孩子進行比較,若是value大則爲LR型,若是value小則爲LL型。若是爲RX型,將value與unbalance右孩子進行比較,若是value大則爲RR型,若是value小則爲RL型。node

可是這種判斷類型的方法實際上存在不足之處,就是它是適用於插入節點致使二叉樹失衡的情形,由於第二步中要用到剛剛插入的節點的值。若是是刪除節點致使的失衡就不能用這種方法判斷了,由於根本沒有value。函數

我在思考刪除節點致使失衡的情形時,發現我上面總結的判斷類型的方法實際上沒有總結到根源上spa

其實咱們調整樹的結構根本目的是爲了下降左右子樹的高度差,也就是說調整的目的在於調整左右子樹的高度(固然在調整高度的同時要保證依然是一顆二叉查找樹)。實際上最小非平衡樹的四種類型,實際上就是對左右子樹高度的一個描述、一個分類3d

好比LL型code

第一個L表示:unbalance的左子樹比右子樹高。第二個L表示unbalance的左孩子的左子樹比右子樹高。blog

 

LR型:排序

L表示:unbalance的左子樹比右子樹高。R表示unbalance的左孩子的右子樹比左子樹高。繼承

 

RL型get

R表示:unbalance的右子樹比左子樹高。L表示unbalance的右孩子的左子樹比右子樹高。class

 

RR型:

第一個R表示:unbalance的右子樹比左子樹高。第二個R表示unbalance的右孩子的右子樹比左子樹高。

 

因此總結一下就是,第一個字母(L或R)描述的是unbalance(也就是根節點)的左右子樹哪一個更高,而第二個字母(L或R)描述的是unbalance的孩子(若是第一個是L則爲左孩子,反之爲右孩子)的左右子樹哪一個更高

這樣,添加節點和刪除節點致使的不平衡問題,對最小非平衡子樹的類型判斷就能夠統一塊兒來了!!!!!

另外須要指出,對於添加節點過程,並不存在,最小非平衡子樹的左右子樹等高的狀況。好比下圖:

 

 

最小非平衡子樹的樹根爲12,可是8節點的左右子樹高度相等,這才插入節點操做中是不可能產生的,由於剛剛插入的節點只多是7或10,可是不管哪一個是剛剛插入的節點,在它插入以前就已經不平衡了。好比10是剛剛插入的節點,能夠看到,在插入10以前,12就已經不平衡了。

可是這種狀況卻可能在刪除節點的過程當中出現,好比下圖:

 

 

樹原本是平衡的,可是刪除了14後,12就不平衡了,而這個時候8節點的左右子樹等高。這種情形也是LL型。因此對上面類型的分類,還須要加入unbalance的孩子的左右子樹等高的狀況,添加以後就是:

LL型:

第一個L表示:unbalance的左子樹比右子樹高。第二個L表示unbalance的左孩子的左子樹比右子樹高,或者unbalance的左孩子的左右子樹等高

 

LR型:

L表示:unbalance的左子樹比右子樹高。R表示unbalance的左孩子的右子樹比左子樹高。

 

RL型:

R表示:unbalance的右子樹比左子樹高。L表示unbalance的右孩子的左子樹比右子樹高。

 

RR型:

第一個R表示:unbalance的右子樹比左子樹高。第二個R表示unbalance的右孩子的右子樹比左子樹高,或者unbalance的右孩子的左右子樹等高

 

理解了上面,下面開始講刪除節點操做

 

節點刪除操做

對於二叉平衡樹的刪除節點操做,能夠分紅兩步:

一、         刪除節點,而且保證依然是一棵二叉排序樹

二、         對二叉平衡樹進行調整,保證是一棵平衡二叉樹

 

對於第二步,在將刪除節點和插入節點致使的非平衡問題中,最小非平衡子樹類型的判斷方法進行了統一後,實際上,對刪除節點致使失衡問題的調整和對於添加節點致使的失衡問題的調整,方法也就統一了!

因此重點在第一步,即:刪除節點,而且保證依然是一棵二叉排序樹

 

當刪除一個節點時,該節點的孩子們怎麼分配十分關鍵,(父親死以前要安排他的孩子,可憐天下父母心呀!)由於要保證依然是一棵二叉排序樹。

 

根據待刪除節點的孩子的分佈特色,能夠將待刪除節點分紅三種類型,咱們設待刪除的節點爲todelete:

一、         todelete沒有孩子,這種狀況最簡單了,直接把它刪了就好,由於它沒有孩子要分配。

二、         todelete只有一個孩子,這種狀況也比較簡單,用這個惟一的孩子將todelete取代了就好,所謂子承父業

三、         todelete有兩個孩子,這種狀況就比較複雜了。俗話說一碗水端不平,究竟將本身的皇位傳給哪一個孩子呢?這但是個嚴肅的問題!中國古代講究宗法制,血統很重要,按照宗法制,皇位最合法的繼承者就是嫡長子!那在二叉排序樹中誰是todelete的嫡長子呢?答案是todelete的後繼節點,也就是比todelete大的節點中的最小的那一個!看到了吧,爲何當初起名字的時候要叫它後繼節點呢。人家是要繼承皇位噠!
太子繼承了皇位,那太子的位置就空了,這個時候就須要有人來繼承太子的位置,那我的就是原太子的右孩子。好把,咱們形式化一下,設todelete的後繼節點爲y,y的右孩子爲x(注意y是沒有左孩子的,由於若是存在左孩子那他的左孩子就是後繼節點,繼承皇位就沒他什麼事兒啦!)。這個時候,若是x爲NULL那麼,將todelete用y的替換,而後釋放原來的y空間便可。若是x存在,那麼用y替換了todelete後,還要用x替換y,而後釋放原來x的空間,也就是太子成爲皇帝,太子的兒子成爲太子,而後太子的兒子的位置就空了,空了就清理了

兩張圖,說明一下:

 

 


這裏要多說一句,對於單鏈表來講,若是用一個節點替換另外一個節點,好比:用C替換B,咱們能夠先斷開AB之間的鏈,而後後將A連接到C,而後斷開BC之間的鏈,最後把B回收。固然咱們也能夠不斷開鏈,而是用C的內容替換B的內容,而後回收C。對於樹來講,也有這兩種方法,可是採用值替換的方法更簡單一下,緣由嘛,是由於,單鏈表就一條鏈,而樹是會分叉的,會有多條鏈的

 

固然還有一點須要注意,就是當後繼節點y是todelete的兒子的時候,和y是todelete的孫子(或者更後的位置)時,且x爲NULL的時候,編寫代碼時會有一點出入。看代碼的時候就明白了(可能你用其餘方法,能夠避免這種差別,也說不定)

 

刪除部分的代碼:

/**

 * 刪除指定的節點

 * */

void delete_node(PBNode root,int value)

{

         //找到該節點

         PBNode node  = get_node(root,value);

         if(node == NULL)

                  return;

         //找到副節點

         PBNode p_node = get_father(root,value);

        

         if(node->l_tree == NULL)

         {

                  PBNode r = node->r_tree;

                  if(r == NULL)//爲葉子節點的狀況

                  {

                          //直接刪除該節點便可

                          if(p_node != root)//反之,說明整個二叉樹就一個根節點

                          {

                                   if(p_node->l_tree == node)

                                   {

                                            p_node->l_tree = NULL;

 

                                   }

 

                                   if(p_node->r_tree == node)

                                   {

                                            p_node->r_tree = NULL;

                                   }

 

                          }

                          free_node(&node);

                  }

                  else//只有右子樹的狀況,採用值替換的方法比較科學

                  {

                          node->l_tree = r->l_tree;

                          node->r_tree = r->r_tree;

                          node->value = r->value;

                          free_node(&r);

 

                  }

         }

         else if(node->r_tree == NULL)//只有左子樹的狀況,採用值替換的方法比較科學

         {

                  PBNode l = node->l_tree;

                  node->l_tree = l->l_tree;

                  node->r_tree = l->r_tree;

                  node->value = l->value;

                  free_node(&l);

 

         }

         else//既有左孩子又有右孩子,這種狀況下我採用的是值交換的方式,這樣比較簡單,若是採用斷鏈再從新指向的方法代碼量就會加大

         {

                  //找到後繼節點

                  PBNode y = node->r_tree;

                  PBNode y_p = y;//用於保存後繼節點的父親節點

                  while(y->l_tree != NULL)

                  {

                          y_p = y;

                          y = y->l_tree;

                  }

 

                  PBNode x = y->r_tree; //後繼節點的右孩子

                  //替換後繼節點和待刪除的節點

                  node->value = y->value;        

 

                  if(x == NULL)//後繼節點沒有右孩子(根據後繼節點的定義能夠知道,後繼節點必定沒有左孩子)

                  {

                          //後繼節點沒有右孩子的狀況,在交換了後記節點和待刪除節點的值後,直接刪除後記節點便可

                          if(y_p == y)//後繼節點就是待刪除節點的右孩子

                          {

                                   node->r_tree = NULL;

 

                          }

                          else

                          {

                                   y_p->l_tree = NULL;//後繼節點是待刪除節點的右子樹的最左節點

                          }

                          free_node(&y);

                  }

                  else

                  {

                          //替換後繼節點的右孩子和後繼節點

                          y->l_tree = x->l_tree;

                          y->r_tree = x->r_tree;

                          y->value = x->value;

                          free_node(&x);

                  }

         }

        

}

 

 

對於第二步,使二叉樹平衡,就再調用一下平衡的函數就好,我已經將刪除節點和添加節點後引發的不平衡問題的處理方法進行了統一。

 

最後附上源文件的連接和密碼(那個bst2.c是包含刪除節點操做的,並且將調整的方法進行了統一)

 連接:http://pan.baidu.com/s/1slyjF6t 密碼:k752

 

若是對你有用,請贊一個吧~~

相關文章
相關標籤/搜索