平衡二叉樹詳解

平衡二叉樹(Balanced Binary Tree)又被稱爲AVL樹(有別於AVL算法),且具備如下性質:它是一 棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,而且左右兩個子樹都是一棵平衡二叉樹。這個方案很好的解決了二叉查找樹退化成鏈表的問題,把插入,查找,刪除的時間複雜度最好狀況和最壞狀況都維持在O(logN)。可是頻繁旋轉會使插入和刪除犧牲掉O(logN)左右的時間,不過相對二叉查找樹來講,時間上穩定了不少。ios

平衡二叉樹大部分操做和二叉查找樹相似,主要不一樣在於插入刪除的時候平衡二叉樹的平衡可能被改變,而且只有從那些插入點到根結點的路徑上的結點的平衡性可能被改變,由於只有這些結點的子樹可能變化。算法

 

平衡二叉樹不平衡的情形:編程

把須要從新平衡的結點叫作α,因爲任意兩個結點最多隻有兩個兒子,所以高度不平衡時,α結點的兩顆子樹的高度相差2.容易看出,這種不平衡可能出如今下面4中狀況中:測試

1.對α的左兒子的左子樹進行一次插入spa

2.對α的左兒子的右子樹進行一次插入code

3.對α的右兒子的左子樹進行一次插入blog

4.對α的右兒子的右子樹進行一次插入遞歸

情形1和情形4是關於α的鏡像對稱,二情形2和情形3也是關於α的鏡像對稱,所以理論上看只有兩種狀況,但編程的角度看仍是四種情形。ci

第一種狀況是插入發生在「外邊」的情形(左左或右右),該狀況能夠經過一次單旋轉完成調整;第二種狀況是插入發生在「內部」的情形(左右或右左),這種狀況比較複雜,須要經過雙旋轉來調整。it

 

調整措施:

1、單旋轉

 

上圖是左左的狀況,k2結點不知足平衡性,它的左子樹k1比右子樹z深兩層,k1子樹中更深的是k1的左子樹x,所以屬於左左狀況。

爲了恢復平衡,咱們把x上移一層,並把z下移一層,但此時實際已經超出了AVL樹的性質要求。爲此,從新安排結點以造成一顆等價的樹。爲使樹恢復平衡,咱們把k2變成這棵樹的根節點,由於k2大於k1,把k2置於k1的右子樹上,而本來在k1右子樹的Y大於k1,小於k2,就把Y置於k2的左子樹上,這樣既知足了二叉查找樹的性質,又知足了平衡二叉樹的性質。

這種狀況稱爲單旋轉。

 

2、雙旋轉

對於左右和右左兩種狀況,單旋轉不能解決問題,要通過兩次旋轉。

對於上圖狀況,爲使樹恢復平衡,咱們須要進行兩步,第一步,把k1做爲根,進行一次右右旋轉,旋轉以後就變成了左左狀況,因此第二步再進行一次左左旋轉,最後獲得了一棵以k2爲根的平衡二叉樹。

 

AVL樹的刪除操做:

同插入操做同樣,刪除結點時也有可能破壞平衡性,這就要求咱們刪除的時候要進行平衡性調整。

刪除分爲如下幾種狀況:

首先在整個二叉樹中搜索要刪除的結點,若是沒搜索到直接返回不做處理,不然執行如下操做:

1.要刪除的節點是當前根節點T。

若是左右子樹都非空。在高度較大的子樹中實施刪除操做。

分兩種狀況:

(1)、左子樹高度大於右子樹高度,將左子樹中最大的那個元素賦給當前根節點,而後刪除左子樹中元素值最大的那個節點。

(1)、左子樹高度小於右子樹高度,將右子樹中最小的那個元素賦給當前根節點,而後刪除右子樹中元素值最小的那個節點。

若是左右子樹中有一個爲空,那麼直接用那個非空子樹或者是NULL替換當前根節點便可。

二、要刪除的節點元素值小於當前根節點T值,在左子樹中進行刪除。

遞歸調用,在左子樹中實施刪除。

這個是須要判斷當前根節點是否仍然知足平衡條件,

若是知足平衡條件,只須要更新當前根節點T的高度信息。

不然,須要進行旋轉調整:

若是T的左子節點的左子樹的高度大於T的左子節點的右子樹的高度,進行相應的單旋轉。不然進行雙旋轉。

三、要刪除的節點元素值大於當前根節點T值,在右子樹中進行刪除。

 

 

下面給出詳細代碼實現:

 

AvlTree.h

  1 #include <iostream>
  2 #include <algorithm>
  3 using namespace std;
  4 #pragma once
  5 
  6 //平衡二叉樹結點
  7 template <typename T>
  8 struct AvlNode
  9 {
 10     T data;
 11     int height; //結點所在高度
 12     AvlNode<T> *left;
 13     AvlNode<T> *right;
 14     AvlNode<T>(const T theData) : data(theData), left(NULL), right(NULL), height(0){}
 15 };
 16 
 17 //AvlTree
 18 template <typename T>
 19 class AvlTree
 20 {
 21 public:
 22     AvlTree<T>(){}
 23     ~AvlTree<T>(){}
 24     AvlNode<T> *root;
 25     //插入結點
 26     void Insert(AvlNode<T> *&t, T x);
 27     //刪除結點
 28     bool Delete(AvlNode<T> *&t, T x);
 29     //查找是否存在給定值的結點
 30     bool Contains(AvlNode<T> *t, const T x) const;
 31     //中序遍歷
 32     void InorderTraversal(AvlNode<T> *t);
 33     //前序遍歷
 34     void PreorderTraversal(AvlNode<T> *t);
 35     //最小值結點
 36     AvlNode<T> *FindMin(AvlNode<T> *t) const;
 37     //最大值結點
 38     AvlNode<T> *FindMax(AvlNode<T> *t) const;
 39 private:
 40     //求樹的高度
 41     int GetHeight(AvlNode<T> *t);
 42     //單旋轉 左
 43     AvlNode<T> *LL(AvlNode<T> *t);
 44     //單旋轉 右
 45     AvlNode<T> *RR(AvlNode<T> *t);
 46     //雙旋轉 右左
 47     AvlNode<T> *LR(AvlNode<T> *t);
 48     //雙旋轉 左右
 49     AvlNode<T> *RL(AvlNode<T> *t);
 50 };
 51 
 52 template <typename T>
 53 AvlNode<T> * AvlTree<T>::FindMax(AvlNode<T> *t) const
 54 {
 55     if (t == NULL)
 56         return NULL;
 57     if (t->right == NULL)
 58         return t;
 59     return FindMax(t->right);
 60 }
 61 
 62 template <typename T>
 63 AvlNode<T> * AvlTree<T>::FindMin(AvlNode<T> *t) const
 64 {
 65     if (t == NULL)
 66         return NULL;
 67     if (t->left == NULL)
 68         return t;
 69     return FindMin(t->left);
 70 }
 71 
 72 
 73 template <typename T>
 74 int AvlTree<T>::GetHeight(AvlNode<T> *t)
 75 {
 76     if (t == NULL)
 77         return -1;
 78     else
 79         return t->height;
 80 }
 81 
 82 
 83 //單旋轉
 84 //左左插入致使的不平衡
 85 template <typename T>
 86 AvlNode<T> * AvlTree<T>::LL(AvlNode<T> *t)
 87 {
 88     AvlNode<T> *q = t->left;
 89     t->left = q->right;
 90     q->right = t;
 91     t = q;
 92     t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1;
 93     q->height = max(GetHeight(q->left), GetHeight(q->right)) + 1;
 94     return q;
 95 }
 96 
 97 //單旋轉
 98 //右右插入致使的不平衡
 99 template <typename T>
100 AvlNode<T> * AvlTree<T>::RR(AvlNode<T> *t)
101 {
102     AvlNode<T> *q = t->right;
103     t->right = q->left;
104     q->left = t;
105     t = q;
106     t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1;
107     q->height = max(GetHeight(q->left), GetHeight(q->right)) + 1;
108     return q;
109 }
110 
111 //雙旋轉 
112 //插入點位於t的左兒子的右子樹
113 template <typename T>
114 AvlNode<T> * AvlTree<T>::LR(AvlNode<T> *t)
115 {
116     //雙旋轉能夠經過兩次單旋轉實現
117     //對t的左結點進行RR旋轉,再對根節點進行LL旋轉
118     RR(t->left);
119     return LL(t);
120 }
121 
122 //雙旋轉
123 //插入點位於t的右兒子的左子樹
124 template <typename T>
125 AvlNode<T> * AvlTree<T>::RL(AvlNode<T> *t)
126 {
127     LL(t->right);
128     return RR(t);
129 }
130 
131 
132 template <typename T>
133 void AvlTree<T>::Insert(AvlNode<T> *&t, T x)
134 {
135     if (t == NULL)
136         t = new AvlNode<T>(x);
137     else if (x < t->data)
138     {
139         Insert(t->left, x);
140         //判斷平衡狀況
141         if (GetHeight(t->left) - GetHeight(t->right) > 1)
142         {
143             //分兩種狀況 左左或左右
144 
145             if (x < t->left->data)//左左
146                 t = LL(t);
147             else                  //左右
148                 t = LR(t);
149         }
150     }
151     else if (x > t->data)
152     {
153         Insert(t->right, x);
154         if (GetHeight(t->right) - GetHeight(t->left) > 1)
155         {
156             if (x > t->right->data)
157                 t = RR(t);
158             else
159                 t = RL(t);
160         }
161     }
162     else
163         ;//數據重複
164     t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1;
165 }
166 
167 template <typename T>
168 bool AvlTree<T>::Delete(AvlNode<T> *&t, T x)
169 {
170     //t爲空 未找到要刪除的結點
171     if (t == NULL)
172         return false;
173     //找到了要刪除的結點
174     else if (t->data == x)
175     {
176         //左右子樹都非空
177         if (t->left != NULL && t->right != NULL)
178         {//在高度更大的那個子樹上進行刪除操做
179 
180             //左子樹高度大,刪除左子樹中值最大的結點,將其賦給根結點
181             if (GetHeight(t->left) > GetHeight(t->right))
182             {
183                 t->data = FindMax(t->left)->data;
184                 Delete(t->left, t->data);
185             }
186             else//右子樹高度更大,刪除右子樹中值最小的結點,將其賦給根結點
187             {
188                 t->data = FindMin(t->right)->data;
189                 Delete(t->right, t->data);
190             }
191         }
192         else
193         {//左右子樹有一個不爲空,直接用須要刪除的結點的子結點替換便可
194             AvlNode<T> *old = t;
195             t = t->left ? t->left: t->right;//t賦值爲不空的子結點
196             delete old;
197         }
198     }
199     else if (x < t->data)//要刪除的結點在左子樹上
200     {
201         //遞歸刪除左子樹上的結點
202         Delete(t->left, x);
203         //判斷是否仍然知足平衡條件
204         if (GetHeight(t->right) - GetHeight(t->left) > 1)
205         {
206             if (GetHeight(t->right->left) > GetHeight(t->right->right))
207             {
208                 //RL雙旋轉
209                 t = RL(t);
210             }
211             else
212             {//RR單旋轉
213                 t = RR(t);
214             }
215         }
216         else//知足平衡條件 調整高度信息
217         {
218             t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1;
219         }
220     }
221     else//要刪除的結點在右子樹上
222     {
223         //遞歸刪除右子樹結點
224         Delete(t->right, x);
225         //判斷平衡狀況
226         if (GetHeight(t->left) - GetHeight(t->right) > 1)
227         {
228             if (GetHeight(t->left->right) > GetHeight(t->left->left))
229             {
230                 //LR雙旋轉
231                 t = LR(t);
232             }
233             else
234             {
235                 //LL單旋轉
236                 t = LL(t);
237             }
238         }
239         else//知足平衡性 調整高度
240         {
241             t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1;
242         }
243     }
244     
245     return true;
246 }
247 
248 //查找結點
249 template <typename T>
250 bool AvlTree<T>::Contains(AvlNode<T> *t, const T x) const
251 {
252     if (t == NULL)
253         return false;
254     if (x < t->data)
255         return Contains(t->left, x);
256     else if (x > t->data)
257         return Contains(t->right, x);
258     else
259         return true;
260 }
261 
262 //中序遍歷
263 template <typename T>
264 void AvlTree<T>::InorderTraversal(AvlNode<T> *t)
265 {
266     if (t)
267     {
268         InorderTraversal(t->left);
269         cout << t->data << ' ';
270         InorderTraversal(t->right);
271     }
272 }
273 
274 //前序遍歷
275 template <typename T>
276 void AvlTree<T>::PreorderTraversal(AvlNode<T> *t)
277 {
278     if (t)
279     {
280         cout << t->data << ' ';
281         PreorderTraversal(t->left);
282         PreorderTraversal(t->right);
283     }
284 }

 

main.cpp

 1 #include "AvlTree.h"
 2 
 3 int main()
 4 {
 5     AvlTree<int> tree;
 6     int value;
 7     int tmp;
 8     cout << "請輸入整數創建二叉樹(-1結束):" << endl;
 9     while (cin >> value)
10     {
11         if (value == -1)
12             break;
13         tree.Insert(tree.root,value);
14     }
15     cout << "中序遍歷";
16     tree.InorderTraversal(tree.root);
17     cout << "\n前序遍歷:";
18     tree.PreorderTraversal(tree.root);
19     cout << "\n請輸入要查找的結點:";
20     cin >> tmp;
21     if (tree.Contains(tree.root, tmp))
22         cout << "已查找到" << endl;
23     else
24         cout << "值爲" << tmp << "的結點不存在" << endl;
25     cout << "請輸入要刪除的結點:";
26     cin >> tmp;
27     tree.Delete(tree.root, tmp);
28     cout << "刪除後的中序遍歷:";
29     tree.InorderTraversal(tree.root);
30     cout << "\n刪除後的前序遍歷:";
31     tree.PreorderTraversal(tree.root);
32 }

 

測試結果:

相關文章
相關標籤/搜索