學習過了二叉查找樹,想必你們有遇到一個問題。例如,將一個數組{1,2,3,4}依次插入樹的時候,造成了圖1的狀況。有創建樹與沒創建樹對於數據的增刪查改已經沒有了任何幫助,反而增添了維護的成本。而只有創建的樹如圖2,纔可以最大地體現二叉樹的優勢。數組

                         

  在上述的例子中,圖2就是一棵平衡二叉樹。科學家們提出平衡二叉樹,就是爲了讓樹的查找性能獲得最大的體現(至少我是這樣理解的,歡迎批評改正)。下面進入今天的正題,平衡二叉樹。數據結構

AVL的定義

  平衡二叉查找樹:簡稱平衡二叉樹。由前蘇聯的數學家Adelse-Velskil和Landis在1962年提出的高度平衡的二叉樹,根據科學家的英文名也稱爲AVL樹。它具備以下幾個性質:post

  1. 能夠是空樹。
  2. 假如不是空樹,任何一個結點的左子樹與右子樹都是平衡二叉樹,而且高度之差的絕對值不超過1

  平衡之意,如天平,即兩邊的份量大約相同。如定義,假如一棵樹的左右子樹的高度之差超過1,如左子樹的樹高爲2,右子樹的樹高爲0,子樹樹高差的絕對值爲2就打破了這個平衡。如依次插入1,2,3三個結點(以下圖)後,根結點的右子樹樹高減去左子樹樹高爲2,樹就失去了平衡。性能

               

  那麼在創建樹的過程當中,咱們如何知道左右子樹的高度差呢?在這裏咱們採用了平衡因子進行記錄。學習

  平衡因子:左子樹的高度減去右子樹的高度。由平衡二叉樹的定義可知,平衡因子的取值只可能爲0,1,-1.分別對應着左右子樹等高,左子樹比較高,右子樹比較高。以下圖3d

   

  說到這裏,咱們已經能夠大概知道平衡二叉樹的結構定義須要什麼內容了,數據成員,平衡因子,以及左右分支。因此,咱們給出以下的結構定義。你們主要首先先了解平衡因子的各個取值及其含義便可。blog

typedef char KeyType;                   //關鍵字排序

typedef struct MyRcdType            //記錄博客

{數學

    KeyType key;

}RcdType,*RcdArr;

typedef enum MyBFStatus                //爲了方便平衡因子的賦值,這裏進行枚舉

{                           //RH,EH,LH分別表示右子樹較高,左右子樹等高,左子樹較高

    RH,EH,LH

}BFStatus;

typedef struct MyBBSTNode       //樹結點類型定義

{

    RcdType data;                             //數據成員

    BFStatus bf;                                 //平衡因子

    struct MyBBSTNode *lchild,*rchild;        //左右分支

}BBSTNode,*BBSTree;

AVL樹的插入時的失衡與調整

前言:這部分的失衡調整是指插入時的失衡與調整。刪除的失衡與調整與插入大體同樣,可是仍是有不少不一樣,在後續章節講解。

1、 失衡與調整的引導

  說了這麼久,咱們開始進入今天的重點,如何將一棵不平衡的二叉樹變成平衡二叉樹(只討論不平衡的是由於假如樹是平衡的就沒必要咱們進行處理)。平衡二叉樹的失衡調整主要是經過旋轉最小失衡子樹來實現的

  最小失衡子樹:在新插入的結點向上查找,以第一個平衡因子的絕對值超過1的結點爲根的子樹稱爲最小不平衡子樹。也就是說,一棵失衡的樹,是有可能有多棵子樹同時失衡的,以下。而這個時候,咱們只要調整最小的不平衡子樹,就可以將不平衡的樹調整爲平衡的樹。

  在圖7中。2結點(左子樹樹高-右子樹樹高)的絕對值=2。同理,3結點的平衡因子也爲2.此時同時存在了兩棵不平衡子樹,而以3爲根的樹是最小的不平衡子樹。咱們只要將其以3爲中心,將最小不平衡樹向左旋轉,便可獲得平衡二叉樹,如圖8。具體方法後續講解。

           

下面咱們先用兩個簡單的例子來感覺一下調整的方法。

例1:右子樹太高,向左旋轉。步驟以下

       i. 將2做爲根結點

      ii. 將1做爲2的左孩子

     iii. 將2的左孩子做爲1的右孩子(維護樹的有序性,只是此處爲NULL而已)

              

例2:左子樹太高,向右旋轉。步驟以下

       i.   將2做爲根結點

      ii.   將3做爲2的右孩子

     iii.   將2的右孩子做爲3的左孩子(維護樹的有序性,只是此處爲NULL而已)

         

下面咱們再來看一個經過旋轉,可是沒辦法達到平衡的失敗例子。

例3:右子樹太高,向左旋轉。步驟以下

      i.   將3做爲根結點

     ii.   將3的左孩子做爲1的右孩子

    iii.   將1做爲3的左孩子

                     

  如上,咱們發現,旋轉以後樹並無恢復平衡。對比圖9,咱們發現,根的右子樹不一致。

  在上面的三個例子咱們能夠看出,咱們對不平衡的樹進行旋轉的時候,不只須要考慮須要最小失衡子樹的根結點的平衡因子,還要考慮根結點較高子樹的根結點的平衡因子。如圖9與圖11中,較高子樹都爲右子樹,右子樹不一樣,旋轉後有着徹底不一樣的結果。

  爲了方便討論,咱們使用連續的兩個字母來表示平衡因子,以表示各類不一樣的狀況。第一個字母表示最小不平衡子樹根結點的平衡因子,第二個字母表示最小不平衡子樹較高子樹的根結點的平衡因子。使用L表示左子樹較高,R表示右子樹較高,E表示左右子樹等高。如上述圖11,根爲的平衡因子L,較高子樹的根爲L,咱們將這種狀況表示爲LL型,再如上述例子3,根爲R,較高子樹的根爲L咱們將這種狀況稱爲RL型。

  下面咱們將對全部的失衡狀況進行討論。大體分爲兩大類,一左子樹太高,二右子樹太高。順帶提一下記憶的方法,讀者對於具體某一種類型只要記住最後哪個結點做爲根便可,也就是下面標紅色的部分。

2、失衡與處理詳解

1. 左子樹太高

  a) LL型

  在LL型的不平衡樹中,咱們首先找到最小不平衡子樹,再以其根結點向右旋轉。爲什麼是向右旋轉呢?應該不難理解,向右旋轉後,至關於右邊的子樹樹高增長了1,而左邊的子樹樹高下降了1,而本來的樹高之差爲2,那麼就可以將根的平衡因子就化爲0.引用一下以前的圖以下。旋轉以後爲「原來根結點的左孩子做爲新的根結點」。

  咱們對樹以根結點爲中心,向右旋轉。旋轉步驟以下

    i.   將2做爲根結點

   ii.   將3做爲2的右孩子

  iii.   將2的右孩子做爲3的左孩子(維護樹的有序性,只是此處爲NULL而已)

           

  旋轉後,3與2的平衡因子爲EH,1的平衡因子保持不變。

  b) LE型

  在這裏須要說明的是,插入的時候,是不會出現LE的這種狀況的。只有在刪除的時候纔會出現。下面對於爲什麼插入不可能出現作一些我的看法。

  咱們不妨假設存在LE的這種狀況。以下。

            

  假設咱們剛插入的元素是1,那麼原來的樹已經不是平衡樹。不可能。

  假設咱們剛插入的元素是2.5,那麼原來的樹也不是平衡樹,也不可能。因此說在插入的時候,是不會出現LE的這種狀況的。而具體何時會出現呢,咱們在刪除的章節進行講解。同理,不可能出現RE的狀況,下面也不進行討論。讀者可使用反證法自行驗證。

  c) LR型

  對於LR,要分爲兩步進行旋。旋轉以後爲「原來根結點的左孩子的右孩子做爲新的根結點」。

  第一以較高子樹的根,即1,爲中心向左旋轉。具體步驟以下。

          i. 將2的左子樹做爲1的右子樹(維護樹的有序性,只是此處爲NULL而已)

         ii.  將1做爲2的左子樹

        iii.  將2做爲3的左子樹

              

  第二以原樹的根,即3爲中心,向右旋轉。最後結果以下

 

  旋轉後,1,2,3的平衡因子變爲0(無需記憶)。再次發表我的意見,平衡因子要用到的時候推一下就行了。

2. 右子樹太高

  a) RR型

  仍是引用一下以前的例子。旋轉的步驟以下。旋轉以後爲「原來根結點的右孩子做爲新的根結點」。

     i.  將2做爲根結點

    ii.  將1做爲2的左孩子

   iii.  將2的左孩子做爲1的右孩子(維護樹的有序性,只是此處爲NULL而已)

        

  最後1,2,3的平衡因子都爲EH。

  b)RL型

  仍是引用一下以前的例子。與LR型相似,咱們須要進行兩次旋轉。旋轉以後爲「原來根結點的右孩子的左孩子做爲新的根結點」。

  第一,以根結點的右孩子即3爲中心向右旋轉,結果以下。具體步驟以下

      i.  將2做爲1的右孩子

     ii.  將3做爲2的右孩子

    iii.   將2的右孩子做爲3的左孩子(維護樹的有序性,只是此處爲NULL而已)

              

  第二,以原根結點即1,做爲中心,向左旋轉。結果以下。具體步驟以下

     i.   將2做爲根結點

    ii.   將1做爲2的左孩子

   iii.   將2的左孩子做爲1的右孩子(維護樹的有序性,只是此處爲NULL而已)

       

  最後1,2,3的平衡因子都會EH

三、  插入時失衡與調整的總結

  1. 在全部的不平衡狀況中,都是按照「尋找最小不平衡樹」->「尋找所屬的不平衡類別」->「根據4種類別進行固定化程序的操做」。
  2. LL,LR,RR,RL其實已經爲咱們提供了最後哪一個結點做爲新的根指明瞭方向。如LR型最後的根結點爲原來的根的左孩子的右孩子,RL型最後的根結點爲原來的根的右孩子的左孩子。咱們只要記住這四種狀況,能夠很快地推導出全部的狀況。
  3. 維護平衡二叉樹,最麻煩的地方在於平衡因子的維護。想要熟悉這個過程,建議讀者多多畫圖,在感官上首先體驗這個過程。

 

  說到這裏,咱們已經瞭解了了解了什麼是平衡二叉樹,插入結點後如何調整平衡二叉樹。咱們數據結構中常常講到的有增刪查改,那麼下面咱們來說解一下如何刪除。

AVL樹的刪除時的失衡與調整

今天心血來潮想要寫這篇博客的緣由主要就在於此。我在網上找了許久,不少人對於AVL樹的查找,插入都講解得很是精彩,可是刪除的時候卻常常貼出一段代碼,比較少有講解,對於我等須要完成做業的學生實在難受,完成做業後就但願可以與你們分享一下。咳咳,咱們迴歸正題。前方高能,喝口水,看一下窗外帥哥美女再繼續看吧。

1、             預備知識

  1.       樹的刪除

假若有一棵二叉查找樹以下,咱們對它進行中序遍歷,能夠獲得1, 2, 2.5, 3。咱們發現,這是一個遞增的序列。假如咱們如今要刪除的結點爲3,在不考慮樹的平衡問題時,應該哪一個結點來做爲頂替3的位置呢呢?答案是:對排序二叉樹進行中序遍歷時,3的直接前驅或者直接後驅。在這裏,就是2.5,因此刪除後,不進行調整的結果如中間圖。假如咱們如今要刪除的結點爲2,在不考慮樹的平衡問題時,1頂替2的位置(假設左孩子優先於右孩子)。最後以下右圖。

具體的步驟以下:

      i.  尋找到要刪除的結點(3)

     ii.  將待刪除結點的直接前驅或者直接後驅賦值給待刪除結點(2.5賦值給3結點)

    iii.  將直接前驅或者直接後驅刪除(將葉子結點的2.5刪除)

         

     因爲咱們今天主要講的是平衡二叉樹的平衡調整,因此這部分就權當給讀者惡補一下。假如讀者仍是不能理解,請先查看一下二叉查找樹的刪除,再繼續往下看。

 2.   平衡因子的預告

  咱們已經知道,平衡因子有且僅有三種取值,LH,RH,EH。對於以下的一棵樹,刪除一個結點後

  a)   本來樹左右子樹等高。根平衡因子的取值變化爲EH->LH,EH->RH。

  b)   本來樹左右子樹不等高,在較高的子樹上進行刪除,根平衡因子的取值變化爲LH->EH,RH->EH。須要注意的是,當根的平衡因子變化爲LH->EH,RH->EH時整棵樹的高度是降低的。最簡單的例子以下。如下兩棵樹,分別刪除1,3後,平衡因子LH->EH,RH->EH。最後樹的高度都降低了。

      

  c)  本來樹左右子樹不等高,在較低的子樹上進行刪除,此時須要對樹進行平衡處理。以下刪除告終點1,獲得右邊的不平衡樹。

      

  3.       什麼會致使樹高下降

  a)   如第2點的的第b項,根的平衡因子由LH->EH,RH->EH時整棵樹的高度是降低的。

  b)   創建在a點以及平衡處理正確的基礎上,對樹進行正確的平衡處理後,樹高會下降。爲何呢?由於其實最小不平衡子樹進行旋轉後,最小不平衡子樹根的平衡因子老是變

  爲EH,或者說,平衡調整老是下降了最小不平衡子樹的高度。舉例以下。樹的高度由原來的3變爲了2.

    

2、             正式進入AVL樹的刪除與調整

 1.       刪除結點致使平衡二叉樹失衡

  AVL樹也是一棵二叉查找樹,因此它的刪除也是創建在二叉查找樹的刪除之上的,只是,咱們須要在不平衡的時候進行調整。而咱們在預備知識的第2點中的C項中已經說起到,假如咱們在較低的子樹上進行刪除,將會直接致使不平衡樹的出現。那麼,咱們須要進行平衡處理的,就在於此種狀況。舉個栗子。

    

  2.       調整不平衡子樹後,致使了更大的不平衡子樹

  假設最小不平衡子樹爲A,它爲雙親結點b的左子樹,而b的平衡因子爲RH。假設咱們如今對A進行了平衡處理,如上所講,進行平衡處理將致使樹高下降。即咱們讓b較矮的子樹變得更矮了。此時對於b而言,一樣也是不平衡的。此時,咱們須要再一次進行一次平衡處理。舉個栗子以下。

  假設咱們刪除告終點6.那麼最小不平衡子樹就是1,3,5對應的二叉樹。它的雙親10的平衡因子爲RH。咱們首先對最小不平衡子樹進行調整,結果如右圖。咱們發現,最小不平衡子樹從根結點的左子樹變成了整棵樹,因此這個時候咱們又要進行一次平衡調整。具體的平衡調整步驟與插入時是一致的,在這裏就贅述。

       

  在講解插入新的結點進行平衡時,說到刪除時與插入時不有着很大的不一樣就在於此。插入時,進行一次平衡處理,整棵樹都會處於平衡狀態,而在刪除時,須要進行屢次平衡處理,才能保證樹處於平衡狀態。

  細心的朋友可能發現,上面右圖中,最小不平衡子樹的較高子樹的平衡因子爲EH。這個時候,就出現了前面插入時說起的不可能出現的失衡狀況。

 3.       失衡與調整的最後一種狀況LE與RE

  LE與RE型的失衡樹,在進行調整的時候,和LL與RR型的旋轉方式是一致的。只是最後初始根結點的平衡因子不爲EH而已。就拿上面的例子而言,調整後的結果以下。初始根結點的平衡因子爲RH。相對應的,假如是LE的狀況,調整後初始根結點的平衡因子爲LH。