1. 程式人生 > >平衡二叉樹,AVL樹之圖解篇

平衡二叉樹,AVL樹之圖解篇

  原文連結:http://www.cnblogs.com/suimeng/p/4560056.html

學習過了二叉查詢樹,想必大家有遇到一個問題。例如,將一個數組{1,2,3,4}依次插入樹的時候,形成了圖1的情況。有建立樹與沒建立樹對於資料的增刪查改已經沒有了任何幫助,反而增添了維護的成本。而只有建立的樹如圖2,才能夠最大地體現二叉樹的優點。

                         

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

AVL的定義

  平衡二叉查詢樹

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

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

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

               

  那麼在建立樹的過程中,我們如何知道左右子樹的高度差呢?在這裡我們採用了平衡因子進行記錄。

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

   

  說到這裡,我們已經可以大概知道平衡二叉樹的結構定義需要什麼內容了,資料成員,平衡因子,以及左右分支。所以,我們給出如下的結構定義。大家主要首先先了解平衡因子的各個取值及其含義即可。

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的結點為根的子樹稱為最小不平衡子樹。也就是說,一棵失衡的樹,是有可能有多棵子樹同時失衡的,如下。而這個時候,我們只要調整最小的不平衡子樹,就能夠將不平衡的樹調整為平衡的樹。

  在圖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型。

  下面我們將對所有的失衡情況進行討論。大致分為兩大類,一左子樹過高,二右子樹過高。順帶提一下記憶的方法,讀者對於具體某一種型別只要記住最後哪一個結點作為根即可,也就是下面標紅色的部分。

二、失衡與處理詳解

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

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

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

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

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

今天心血來潮想要寫這篇部落格的原因主要就在於此。我在網上找了許久,很多人對於AVL樹的查詢,插入都講解得非常精彩,但是刪除的時候卻經常貼出一段程式碼,比較少有講解,對於我等需要完成作業的學生實在難受,完成作業後就希望能夠與大家分享一下。咳咳,我們迴歸正題。前方高能,喝口水,看一下窗外帥哥美女再繼續看吧。

一、             預備知識

  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.

    

二、             正式進入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。

          

  假如你看到了這個地方,請先為疲憊不堪的自己鼓鼓掌。本篇就到此結束,下一篇將為大家帶來具體的C程式碼實現。另外,這是followDreamLgx第一次寫部落格,希望大家批評改正。

相關推薦

AVL平衡查找

出現 尋找 findmi 有意 出了 操作 amp 為什麽 9.png 首先要說AVL樹,我們就必須先說二叉查找樹,先介紹二叉查找樹的一些特性,然後我們再來說平衡樹的一些特性,結合這些特性,然後來介紹AVL樹。 一、二叉查找樹 1、二叉樹查找樹的相關特征定義 二叉樹查找樹,

平衡,AVL圖解

  原文連結:http://www.cnblogs.com/suimeng/p/4560056.html 學習過了二叉查詢樹,想必大家有遇到一個問題。例如,將一個數組{1,2,3,4}依次插入樹的時候,形成了圖1的情況。有建立樹與沒建立樹對於資料的增刪查改已經沒有了任何

2-平衡查詢AVL

一、AVL樹定義         在資料結構中,AVL樹是最先發明的自平衡二叉查詢樹。在AVL樹中任何節點的兩個子樹的高度差的絕對值不能超過一,所以它也被稱為高度平衡樹。查詢、插入和刪除在平均和最壞情況下都是O(log n)。增加和刪除可能需要通過一次

資料結構平衡(AVL)

背景 不同結構的二叉查詢樹,查詢效率有很大的不同。如何解決這個問題呢?關鍵在於如何最大限度的減小樹的深度。正是基於這個想法,平衡二叉樹出現了。 前言 平衡二叉搜尋樹(英語:Balanced Binary Tree)是一種結構平衡的二叉搜尋樹。 它能在O(log n)時間內完成插入、查詢和

平衡AVLAVL() C++的實現

3、旋轉 在進行插入和刪除之前需要先了解AVL樹的旋轉操作。旋轉操作主要包括LL(左左)旋轉、LR(左右)旋轉、RR(右右)旋轉、RL(右左)旋轉,LL旋轉與RR旋轉對稱,LR旋轉與RL旋轉對稱。旋轉操作是在插入結點或刪除結點導致原AVL樹不平衡時進行的。我的理解是當二叉樹失衡的原因出現在“最低失衡根結點左

Java資料結構 AVL平衡)簡析

AVL(即平衡二叉樹)樹是帶有平衡條件的二叉查詢樹(二叉查詢樹即左孩子小於根節點,右孩子大於根節點的二叉樹)。一顆AVL樹是其每個節點的左子樹和右子樹的高度最多差 1 的二叉查詢樹(空樹的高度定為-1),只有一個節點的樹高度為0。在高度為h的AVL樹中,最少節點數S(h)=S

圖解平衡AVL)程式碼實現

一、平衡二叉樹的概念 對於二叉樹進行查詢的時間複雜度是由查詢過程中的比較次數來衡量的 比較是從根結點到葉節點的路徑進行的,取決於樹的深度,樹深在最好的情況下是O(logN) 當二叉樹退化成一棵單枝樹的情況下,查詢的複雜度將是線性的O(N) 假定二叉搜尋樹中每個結

資料結構---C語言實現平衡AVL

//AVL(自動平衡二叉樹) #include <stdio.h> #include <stdlib.h> typedef int ElemType; //每個結點的平均值 typedef enum {      EH = 0,      LH =

java資料結構與演算法平衡(AVL)的設計與實現

關聯文章:   上一篇博文中,我們詳細地分析了樹的基本概念以及二叉查詢樹的實現過程,基於二叉查詢樹的特性,即對於樹種的每個結點T(T可能是父結點),它的左子樹中所有項的值小T中的值,而它的右子樹中所有項的值都大於T中的值。這意味著該樹所有的元素可以用某

平衡AVL圖解與實現

平衡二叉樹(Balanced BinaryTree)又被稱為AVL樹。它具有以下性質:它是一棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,並且左右兩個子樹都是一棵平衡二叉樹。 平衡二叉樹一般是一個有序樹,它具有二叉樹的所有性質,其遍歷操作和二叉樹的遍歷操作相同。

【資料結構】平衡AVL

平衡二叉排序樹 平衡二叉排序樹(Balanced Binary Sort Tree),上一篇部落格【資料結構】二叉排序樹BST講了BST,並且在最後我們說BST上的操作不會超過O(h),既然樹高這麼重要,那麼BBST的研究就是為了使得樹的深度在可接受的範圍內漸近意義下達到O

資料結構AVL平衡

平衡二叉樹(Balanced Binary Tree)又被稱為AVL樹(有別於AVL演算法),且具有以下性質:它是一 棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,並且左右兩個子樹都是一棵平衡二叉樹。這個方案很好的解決了二叉查詢樹退化成連結串列的問題,把插入,查詢,刪除的時間複雜度最

Javascript資料結構與演算法的自平衡搜尋AVL)實現

Javascript之資料結構與演算法的自平衡二叉搜尋樹(AVL)實現 簡介 程式碼實現 簡介 AVL樹是一種自平衡樹。新增或移除節點時, AVL樹會嘗試自平衡。任意一個節點(不論深 度)的左子樹和右子樹高度最多相差1

資料結構 AVL平衡)(C語言實現)

AVL樹(平衡二叉樹) 1. AVL樹定義和性質 AVL(Adelson-Velskii和Landis發明者的首字母)樹時帶有平衡條件的二叉查詢樹。 二叉查詢樹的效能分析: 在一顆左右子樹高度平衡情況下,最優的時間複雜度為O(log2n),這與這半

看圖說話平衡排序(AVL)

看圖說話之平衡二叉排序樹 本文在看圖說話之二叉排序樹的基礎上介紹了平衡二叉排序樹,結構性較好的二叉排序樹其插入和刪除操作的時間複雜度接近Log(N),但是存在某些特定的情況二叉排序樹會退化到單鏈表的情況,比如由順序或者逆序或者基本有序的陣列構建的排序二叉樹,此時插入和刪除操

平衡AVL的旋轉

平衡二叉樹是基於二叉排序樹(或者也叫二叉搜尋樹)實現的一種自平衡的二叉樹,實現方法有比如:AVL樹、紅黑樹等等 二叉搜尋樹定義(維基百科): 二叉查詢樹(英語:Binary Search Tree),也稱二叉搜尋樹、有序二叉樹(英語:ordered bina

平衡AVL的實現(c++STL)

pre 根節點 code 先序 blog ltr ons void 過程 #include <iostream> using namespace std; template<class Type> class AVLtree;

平衡AVL)與紅黑

數組 條件 節點 avl樹 平衡因子 src 特性 復雜度 關聯數組 一、AVL樹性質1.本身首先是一棵二叉搜索樹。2.帶有平衡條件:每個結點的左右子樹的高度之差的絕對值(平衡因子)最多為1。也就是說,AVL樹,本質上是帶了平衡功能的二叉查找樹(二叉排序樹,二叉搜索樹)。A

查找AVL

結構 ima div info 四種 分享圖片 查找 pos image AVL樹插入數據的四種結構: 第一種: 第二種: 第三種: 第四種: 二叉查找樹之AVL樹

數據結構 平衡avl c++

歸納 all AI 例子 大於 樹節點 fin 深度 UC 平衡二叉樹:一顆空樹,或者是具有以下性質的二叉樹 左子樹和右子樹都是平衡二叉樹 左子樹和右子樹的深度只差不超過1 把二叉樹節點的平衡因子BF(Balance Factor)定義為該節點的左子樹深度減去右子樹深度