圖解數據結構樹之AVL樹

AVL樹(平衡二叉樹):

  AVL樹本質上是一顆二叉查找樹,可是它又具備如下特色:它是一棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,而且左右兩個子樹都是一棵平衡二叉樹。在AVL樹中任何節點的兩個子樹的高度最大差異爲一,因此它也被稱爲平衡二叉樹。下面是平衡二叉樹和非平衡二叉樹對比的例圖:ios

  平衡因子(bf):結點的左子樹的深度減去右子樹的深度,那麼顯然-1<=bf<=1;算法

AVL樹的做用:

  咱們知道,對於通常的二叉搜索樹(Binary Search Tree),其指望高度(即爲一棵平衡樹時)爲log2n,其各操做的時間複雜度(O(log2n))同時也由此而決定。可是,在某些極端的狀況下(如在插入的序列是有序的時),二叉搜索樹將退化成近似鏈或鏈,此時,其操做的時間複雜度將退化成線性的,即O(n)。咱們能夠經過隨機化創建二叉搜索樹來儘可能的避免這種狀況,可是在進行了屢次的操做以後,因爲在刪除時,咱們老是選擇將待刪除節點的後繼代替它自己,這樣就會形成老是右邊的節點數目減小,以致於樹向左偏沉。這同時也會形成樹的平衡性受到破壞,提升它的操做的時間複雜度。
  例如:咱們按順序將一組數據1,2,3,4,5,6分別插入到一顆空二叉查找樹和AVL樹中,插入的結果以下圖:
        

 

 

 

 

 

 

 

  由上圖可知,一樣的結點,因爲插入方式不一樣致使樹的高度也有所不一樣。特別是在帶插入結點個數不少且正序的狀況下,會致使二叉樹的高度是O(N),而AVL樹就不會出現這種狀況,樹的高度始終是O(lgN).高度越小,對樹的一些基本操做的時間複雜度就會越小。這也就是咱們引入AVL樹的緣由數據結構

AVL樹的基本操做:

  AVL樹的操做基本和二叉查找樹同樣,這裏咱們關注的是兩個變化很大的操做:插入和刪除!spa

  咱們知道,AVL樹不只是一顆二叉查找樹,它還有其餘的性質。若是咱們按照通常的二叉查找樹的插入方式可能會破壞AVL樹的平衡性。同理,在刪除的時候也有可能會破壞樹的平衡性,因此咱們要作一些特殊的處理,包括:單旋轉和雙旋轉!3d

  AVL樹的插入,單旋轉的第一種狀況---右旋:code

  由上圖可知:在插入以前樹是一顆AVL樹,而插入以後結點T的左右子樹高度差的絕對值再也不 < 1,此時AVL樹的平衡性被破壞,咱們要對其進行旋轉。由上圖可知咱們是在結點T的左結點的左子樹上作了插入元素的操做,咱們稱這種狀況爲左左狀況,咱們應該進行右旋轉(只需旋轉一次,故是單旋轉)。具體旋轉步驟是:blog

  T向右旋轉成爲L的右結點,同時,Y放到T的左孩子上。這樣便可獲得一顆新的AVL樹,旋轉過程圖以下:遞歸

 

  左左狀況的右旋舉例:it

  AVL樹的插入,單旋轉的第一種狀況---左旋:io

 

   由上圖可知:在插入以前樹是一顆AVL樹,而插入以後結點T的左右子樹高度差的絕對值再也不 < 1,此時AVL樹的平衡性被破壞,咱們要對其進行旋轉。由上圖可知咱們是在結點T的右結點的右子樹上作了插入元素的操做,咱們稱這種狀況爲右右狀況,咱們應該進行左旋轉(只需旋轉一次,故事單旋轉)。具體旋轉步驟是:

   T向右旋轉成爲R的左結點,同時,Y放到T的左孩子上。這樣便可獲得一顆新的AVL樹,旋轉過程圖以下:

 

  右右狀況的左旋舉例:

  以上就是插入操做時的單旋轉狀況!咱們要注意的是:誰是T誰是L,誰是R還有誰是X,Y,Z!T始終是開始不平衡的左右子樹的根節點。顯然L是T的左結點,R是T的右節點。X、Y、Y是子樹固然也能夠爲NULL.NULL歸NULL,但不能破壞插入時我上面所說的左左狀況或者右右狀況。

  AVL樹的插入,雙旋轉的第一種狀況---左右(先左後右)旋:

 

由  上圖可知,咱們在T結點的左結點的右子樹上插入一個元素時,會使得根爲T的樹的左右子樹高度差的絕對值再也不 < 1,若是隻是進行簡單的右旋,獲得的樹仍然是不平衡的。咱們應該按照以下圖所示進行二次旋轉:

  

  左右狀況的左右旋轉實例:

  AVL樹的插入,雙旋轉的第二種狀況---右左(先右後左)旋:

  由上圖可知,咱們在T結點的右結點的左子樹上插入一個元素時,會使得根爲T的樹的左右子樹高度差的絕對值再也不 < 1,若是隻是進行簡單的左旋,獲得的樹仍然是不平衡的。咱們應該按照以下圖所示進行二次旋轉:

  右左狀況的右左旋轉實例:

AVL樹的插入代碼實現:(僅供參考)

  懂了以上單旋轉和雙旋轉的原理以後,那麼代碼寫起來也就比較簡單了,如下是我寫的代碼,若是有錯還望你們不吝指正。(參考數據結構與算法分析-Weiss著)

  1 #include <iostream>
  2 
  3 using namespace std;
  4 
  5 #define DataType int
  6 
  7 /*
  8     定義AVL樹的結構體,鏈式
  9 */
 10 typedef struct AvlNode{
 11     DataType    data;
 12     AvlNode    * m_pLeft;
 13     AvlNode    * m_pRight;
 14     int height;
 15 }*AvlTree,*Position,AvlNode;
 16 
 17 //求兩個數的最大值
 18 int Max(int a,int b)
 19 {
 20     return a>b?a:b;
 21 }
 22 //求樹的高度
 23 int Height( AvlTree T)
 24 {
 25     if(NULL == T)
 26         return -1;
 27     else
 28         return T->height;
 29 }
 30 
 31 //單旋轉右旋
 32 AvlTree singleRotateWithRight(AvlTree T)
 33 {
 34     AvlTree L = T->m_pLeft;
 35     T->m_pLeft = L->m_pRight;
 36     L->m_pRight = T;
 37     T->height = Max( Height(T->m_pLeft),Height(T->m_pRight) ) + 1;
 38     L->height = Max( Height(L->m_pLeft),Height(L->m_pRight) ) + 1;
 39     return L;    //此時L成爲根節點了(可參考AVL的插入的左左狀況的右旋圖)
 40 }
 41 //單旋轉左旋
 42 AvlTree singleRotateWithLeft(AvlTree T)
 43 {
 44     AvlTree R = T->m_pRight;
 45     T->m_pRight = R->m_pLeft;
 46     R->m_pLeft = T;
 47     T->height = Max( Height(T->m_pLeft),Height(T->m_pRight) ) + 1;
 48     R->height = Max( Height(R->m_pLeft),Height(R->m_pRight) ) + 1;
 49     return R;    //此時R成爲根節點了(可參考AVL的插入的左左狀況的左旋圖)
 50 }
 51 //雙旋轉,先左後右
 52 AvlTree doubleRotateWithLeft(AvlTree T)        //先左後右
 53 {
 54     T->m_pLeft = singleRotateWithLeft(T->m_pLeft);
 55     return singleRotateWithRight(T);
 56 }
 57 //雙旋轉,先右後左
 58 AvlTree doubleRotateWithRight(AvlTree T)    //先右後左
 59 {
 60     T->m_pRight = singleRotateWithRight(T->m_pRight);
 61     return singleRotateWithLeft(T);
 62 }
 63 AvlTree AvlTreeInsert(AvlTree T, DataType x)
 64 {
 65     if(T == NULL)    //若是樹爲空
 66     {
 67         T = (AvlNode *)malloc(sizeof(struct AvlNode));
 68         if(T)
 69         {
 70             T->data = x;
 71             T->m_pLeft    = NULL;
 72             T->m_pRight = NULL;
 73             T->height = 0;
 74         }
 75         else
 76         {
 77             cout << "空間不夠" << endl;
 78             exit(0);
 79         }
 80     }
 81     else if( x < T->data)        //若是插入到T結點的左子樹上
 82     {
 83         T->m_pLeft = AvlTreeInsert(T->m_pLeft,x);    //先插入,後旋轉
 84         if(Height(T->m_pLeft) - Height(T->m_pRight) == 2) //只有多是這個
 85         {
 86             if(x < T->m_pLeft->data)        //左左狀況,只須要右旋轉
 87             {
 88                 T = singleRotateWithRight( T );
 89             }
 90             else                            //左右狀況,雙旋轉,先左
 91             {            
 92                 T = doubleRotateWithLeft( T );
 93             }
 94         }
 95     }
 96     else if( x > T->data )
 97     {
 98         T->m_pRight = AvlTreeInsert(T->m_pRight,x);
 99         if(Height(T->m_pRight) - Height(T->m_pLeft) == 2)
100         {
101             if(x > T->m_pRight->data)        //右右狀況,進行左旋
102             {
103                 T = singleRotateWithLeft( T );
104             }
105             else                            //左右狀況,雙旋轉,先右
106             {
107                 T = doubleRotateWithRight( T );
108             }
109         }
110     }
111     //若是這個數已經存在,那麼不進行插入
112     T->height = Max(Height(T->m_pLeft),Height(T->m_pRight)) + 1;
113     return T;
114 }
115 //遞歸實現中序遍歷
116 void inOrderVisitUseRecur(const AvlTree pCurrent)
117 {
118     if(pCurrent)
119     {
120         inOrderVisitUseRecur(pCurrent->m_pLeft);
121         cout << pCurrent->data << " ";
122         if(pCurrent->m_pLeft)
123             cout << " leftChild: "<<pCurrent->m_pLeft->data;
124         else
125             cout << " leftChild: "<<"NULL" ;
126         if(pCurrent->m_pRight)
127             cout << " rightChild: "<<pCurrent->m_pRight->data;
128         else
129             cout << " rightChild: "<< "NULL";
130         cout << endl;
131         inOrderVisitUseRecur(pCurrent->m_pRight);
132     }
133 }
134 int main()
135 {
136     AvlTree root = NULL;
137     root = AvlTreeInsert(root,1);
138     root = AvlTreeInsert(root,2);
139     root = AvlTreeInsert(root,3);
140     root = AvlTreeInsert(root,4);
141     root = AvlTreeInsert(root,5);
142     root = AvlTreeInsert(root,6);
143     root = AvlTreeInsert(root,7);
144     root = AvlTreeInsert(root,8);
145     root = AvlTreeInsert(root,9);
146     root = AvlTreeInsert(root,10);
147     root = AvlTreeInsert(root,11);
148     root = AvlTreeInsert(root,12);
149     root = AvlTreeInsert(root,13);
150     root = AvlTreeInsert(root,14);
151     root = AvlTreeInsert(root,15);
152     inOrderVisitUseRecur(root);
153     return 0;
154 }
相關文章
相關標籤/搜索