AVL樹本質上是一顆二叉查找樹,可是它又具備如下特色:它是一棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,而且左右兩個子樹都是一棵平衡二叉樹。在AVL樹中任何節點的兩個子樹的高度最大差異爲一,因此它也被稱爲平衡二叉樹。下面是平衡二叉樹和非平衡二叉樹對比的例圖:ios
平衡因子(bf):結點的左子樹的深度減去右子樹的深度,那麼顯然-1<=bf<=1;算法
由上圖可知,一樣的結點,因爲插入方式不一樣致使樹的高度也有所不一樣。特別是在帶插入結點個數不少且正序的狀況下,會致使二叉樹的高度是O(N),而AVL樹就不會出現這種狀況,樹的高度始終是O(lgN).高度越小,對樹的一些基本操做的時間複雜度就會越小。這也就是咱們引入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,若是隻是進行簡單的左旋,獲得的樹仍然是不平衡的。咱們應該按照以下圖所示進行二次旋轉:
右左狀況的右左旋轉實例:
懂了以上單旋轉和雙旋轉的原理以後,那麼代碼寫起來也就比較簡單了,如下是我寫的代碼,若是有錯還望你們不吝指正。(參考數據結構與算法分析-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 }