Avl树

一 Avl树的性质

  Avl树是带有平衡条件的二叉查找树,即Avl树中的每个节点的左子树和右子树的高度最多差1,为此,我们需要在Avl的节点域中记录height信息,此时Avl树节点的域有data、left、right、parent、height等5种信息。

  计算当前节点的height时,只需计算左子节点与右子节点的高度较高者,并在此基础上加1即可。若节点不存在,则将高度定义为-1,由此可知叶子节点的高度为0。

 1 int height(BinaryTreeNode *n)
 2 {
 3     return n ? n->height : -1;
 4 }
 5     
 6 int maxHeight(BinaryTreeNode *n)
 7 {
 8     int lh = height(n->left);
 9     int rh = height(n->right);
10     return lh > rh ? lh+1 : rh+1;
11 }

  一棵Avl树的高度最多为1.44log(N+2)-1.328。

  容易看出,插入或删除节点操作后,将有4种情况使Avl树失衡,假设失衡的节点为n,则有:

    ① n的左子树比右子树的高度高2,且n的左子节点的左子树高度大于右子树

    ② n的左子树比右子树的高度高2,且n的左子节点的右子树高度大于左子树

    ③ n的右子树比左子树的高度高2,且n的右子节点的左子树高度大于右子树

    ④ n的右子树比左子树的高度高2,且n的右子节点的右子树高度大于左子树

二 Avl树的再平衡操作

  对于以上四种情况,都可以采用左旋、右旋、左右双旋、右左双旋的操作使树再平衡。下面,我们来详细分析这四种情况:

  1 n的左子树比右子树的高度高2,且n的左子节点的左子树高度大于右子树

  

  此时,对于k2需要采用右旋操作,具体步骤如下

    ① 若k1的右子节点y存在,则使y的parent指向k2,k2的left指向y;若y不存在,k2的left为NULL。

    ② 将k1的parent指向k2的parent;若k2的parent为NULL(即k2为root),那么设root=k1,否则,设置k2->parent的left/right为k1。

    ③ 将k2的parent指向k1,将k1->right指向k2。

    ④ 重新计算k1、k2的高度

 1 void rotateWithLeftChild(BinaryTreeNode *k2)
 2 {
 3     BinaryTreeNode *k1 = k2->left;
 4     if (k1->right)
 5         k1->right->parent = k2;
 6     k2->left = k1->right;
 7     k1->parent = k2->parent;
 8     if (!k2->parent)
 9         root = k1;
10     else if (k2 == k2->parent->left)
11         k2->parent->left = k1;
12     else if (k2 == k2->parent->right)
13         k2->parent->right = k1;
14     else
15         ;
16     k2->parent = k1;
17     k1->right = k2;
18     k1->height = maxHeight(k1);
19     k2->height = maxHeight(k2);
20 }

  2 n的右子树比左子树的高度高2,且n的右子节点的右子树高度大于左子树

  

 

  

  此时,对于k1需要采用右旋操作,具体步骤如下

    ① 若k2的左子节点y存在,则使y的parent指向k1,k1的right指向y;若y不存在,k1的right为NULL。

    ② 将k2的parent指向k1的parent;若k1的parent为NULL(即k1为root),那么设root=k2,否则,设置k1->parent的left/right为k2。

    ③ 将k1的parent指向k2,将k2->left指向k1。

    ④ 重新计算k1、k2的高度

 1 void rotateWithRightChild(BinaryTreeNode *k1)
 2 {
 3     BinaryTreeNode *k2 = k1->right;
 4     if (k2->left)
 5         k2->left->parent = k1;
 6     k1->right = k2->left;
 7     k2->parent = k1->parent;
 8     if (!k1->parent)
 9         root = k2;
10     else if (k1 == k1->parent->left)
11         k1->parent->left = k2;
12     else if (k2 == k2->parent->right)
13         k1->parent->right = k2;
14     else
15         ;
16     k1->parent = k2;
17     k2->left = k1;
18     k1->height = maxHeight(k1);
19     k2->height = maxHeight(k2);
20 }

  3 n的左子树比右子树的高度高2,且n的左子节点的右子树高度大于左子树

  

 

  此时需要对k3采用左右双旋操作,具体步骤如下

    ① 对k1采用左旋操作

    ② 对k3采用右旋操作

 

1 void doubleRotateWithLeftChild(BinaryTreeNode *k3)
2 {
3     rotateWithRightChild(k3->left);
4     rotateWithLeftChild(k3);
5 }

 

  4 n的右子树比左子树的高度高2,且n的右子节点的左子树高度大于右子树

  

  

  此时需要对k1采用右左双旋操作,具体步骤如下

    ① 对k3采用右旋操作

    ② 对k1采用左旋操作

 

1 void doubleRotateWithRightChild(BinaryTreeNode *k1)
2 {
3     rotateWithLeftChild(k1->right);
4     rotateWithRightChild(k1);
5 }

 

三 Avl树的插入、删除操作

  1 insert插入操作

  在Avl树中插入节点时,除了进行二叉查找树的插入操作外,插入操作结束后需要:

    ①重新计算高度

    ②并根据高度差决定是否需要再平衡操作(若插入的是根节点,则不需要②③)

    ③如果需要再平衡,那么需要采用哪种旋转操作。

  由于采用递归的实现方式,对失衡的节点进行再平衡操作后,还需向上搜索失衡节点直到根节点,从而保证了Avl树的性质。

 1 void insert(Comparable d)
 2 {
 3     if (root)
 4         insertNode(d, root);
 5     else
 6         root = new BinaryTreeNode(d);
 7     
 8     root->height = maxHeight(root);
 9 }
10 
11 void insertNode(Comparable d, BinaryTreeNode *n)
12 {
13     if (d < n->data)
14     {
15         if (n->left)
16             insertNode(d, n->left);
17         else
18         {
19             n->left = new BinaryTreeNode(d);
20             n->left->parent = n;
21         }
22         n->left->height = maxHeight(n->left);
23         if (height(n->left) - height(n->right) == 2)
24         {
25             if (d < n->left->data)
26                 rotateWithLeftChild(n);
27             else
28                 doubleRotateWithLeftChild(n);
29         }
30     }
31     else if (d > n->data)
32     {
33         if (n->right)
34             insertNode(d, n->right);
35         else
36         {
37             n->right = new BinaryTreeNode(d);
38             n->right->parent = n;
39         }
40         n->right->height = maxHeight(n->right);
41         if (height(n->right) - height(n->left) == 2)
42         {
43             if (d > n->right->data)
44                 rotateWithRightChild(n);
45             else
46                 doubleRotateWithRightChild(n);
47         }
48     }
49     else
50         ;
51 }

  2 remove移除操作

  在Avl树中移除节点时,除了进行二叉树的移除操作外,移除操作后还需要:

    ① 向上遍历重新计算父节点的高度直到根节点。

    ② 并根据高度差决定是否需要再平衡操作

    ③ 如果需要再平衡,那么需要采用哪种旋转操作。

  由于移除节点时不是逐层向下递归,所以再平衡操作需要重新编写向上逐层搜索的递归函数。

 1 void remove(Comparable d)
 2 {
 3     BinaryTreeNode *n = searchNode(d);
 4         
 5     if (n != NULL)
 6     {
 7         removeNode(n);
 8     }
 9 }
10 
11 void removeNode(BinaryTreeNode *n)
12 {
13     if (!n)
14         return;
15     if (n->left && n->right)
16     {
17         //n->data = findPredeNode(n)->data;
18         //removeNode(findPredeNode(n));
19         n->data = findSucNode(n)->data;
20         removeNode(findSucNode(n));
21     }
22     else
23     {
24         BinaryTreeNode *x = (n->left) ? n->left : n->right;
25         if (n == root)
26             root = x;
27         else
28         {
29             BinaryTreeNode *p = n->parent;
30 
31             if (n == p->left)
32                 p->left = x;
33             else
34                 p->right = x;
35 
36             delete n;
37             n = NULL;
38             if (x)
39                 x->parent = p;
40             decreaseHeight(p);
41         }
42     }
43 }
44 
45 void decreaseHeight(BinaryTreeNode *n)
46 {
47     if (n)
48     {
49         n->height = maxHeight(n);
50             
51         if ((height(n->left) - height(n->right)) == 2 )
52         {
53             if (height(n->left->right) > height(n->left->left))
54                 doubleRotateWithLeftChild(n);
55             else
56                 rotateWithLeftChild(n);
57         }
58         else if ((height(n->right) - height(n->left)) == 2)
59         {
60             if (height(n->right->left) > height(n->right->right))
61                 doubleRotateWithRightChild(n);
62             else
63                 rotateWithRightChild(n);
64         }
65         else
66             ;
67             
68         decreaseHeight(n->parent);
69     }
70 }

四 完整代码

4.1 AvlTree.hpp

  1 #include <iostream>
  2 
  3 using namespace std;
  4 
  5 //Comparable必须重载 ① '>' ② '<' ③ '==' ④ '<<'
  6 template <typename Comparable>
  7 class AvlTree
  8 {
  9 public:
 10     AvlTree() { root = NULL; }
 11     AvlTree(const AvlTree *bst) { root = deepClone(bst->root); }
 12     ~AvlTree() { makeEmpty(); }
 13     
 14     AvlTree* operator=(const AvlTree *bst)
 15     {
 16         this->root = deepClone(bst->root);
 17         return this;
 18     }
 19     
 20     Comparable findMin()
 21     {
 22         // 方法一
 23         BinaryTreeNode *r = root;
 24         BinaryTreeNode *p = NULL;
 25         while (r)
 26         {
 27             p = r;
 28             r = r->left;
 29         }
 30         if (p)
 31             return p->data;
 32         else
 33             return -1;
 34         // 方法二
 35         //return findMinNode(root)->data;
 36     }
 37     
 38     Comparable findMax()
 39     {
 40         // 方法一
 41         BinaryTreeNode *r = root;
 42         BinaryTreeNode *p = NULL;
 43         while (r)
 44         {
 45             p = r;
 46             r = r->right;
 47         }
 48         if (p)
 49             return p->data;
 50         else
 51             return -1;
 52         // 方法二
 53         //return findMaxNode(root)->data;
 54     }
 55     
 56     bool contains(Comparable d)
 57     {
 58         // 方法一
 59         BinaryTreeNode *r = root;
 60         while (r)
 61         {
 62             if (d < r->data)
 63                 r = r->left;
 64             else if (d > r->data)
 65                 r = r->right;
 66             else
 67                 return true;
 68         }
 69         return false;
 70         // 方法二
 71         //return searchNode(d) ? true : false;
 72     }
 73     
 74     Comparable findPredecessor(Comparable d)
 75     {
 76         BinaryTreeNode *n = searchNode(d);
 77         if (n)
 78         {
 79             BinaryTreeNode *pre = findPredeNode(n);
 80             
 81             if (pre)
 82                 return pre->data;
 83             else
 84                 return n->data;
 85         }
 86         else
 87             return d;
 88     }
 89     
 90     Comparable findSuccessor(Comparable d)
 91     {
 92         BinaryTreeNode *n = searchNode(d);
 93         if (n)
 94         {
 95             BinaryTreeNode *suc = findSucNode(n);
 96             
 97             if (suc)
 98                 return suc->data;
 99             else
100                 return n->data;
101         }
102         else
103             return d;
104     }
105     
106     bool isEmpty()
107     {
108         return root ? false : true;
109     }
110     
111     void makeEmpty()
112     {
113         makeEmpty(root);
114     }
115 
116     void insert(Comparable d)
117     {
118         if (root)
119             insertNode(d, root);
120         else
121             root = new BinaryTreeNode(d);
122         
123         root->height = maxHeight(root);
124     }
125     
126     void remove(Comparable d)
127     {
128         BinaryTreeNode *n = searchNode(d);
129         
130         if (n != NULL)
131         {
132             removeNode(n);
133         }
134     }
135     
136     void printTree()
137     {
138         if (root)
139         {
140             printTree(root);
141             cout << endl;
142         }
143         else
144             cout << "树中没有数据" << endl;
145     }
146 
147 private:
148     struct BinaryTreeNode
149     {
150         Comparable data;
151         BinaryTreeNode *left;
152         BinaryTreeNode *right;
153         BinaryTreeNode *parent;
154         int height;
155         
156         BinaryTreeNode(Comparable d, BinaryTreeNode *l=NULL, BinaryTreeNode *r=NULL, BinaryTreeNode *p=NULL, int h=0): data(d), left(l), right(r), parent(p), height(h) { }
157     };
158 
159     BinaryTreeNode *root;
160     
161     BinaryTreeNode* deepClone(BinaryTreeNode *n)
162     {
163         if (n)
164         {
165             BinaryTreeNode *p = new BinaryTreeNode(n->data, deepClone(n->left), deepClone(n->right), NULL, n->height);
166             if (p->left)
167                 p->left->parent = p;
168             if (p->right)
169                 p->right->parent = p;
170             return p;
171         }
172         return NULL;
173     }
174     
175     BinaryTreeNode* findMinNode(BinaryTreeNode *n)
176     {
177         if (n->left)
178             return findMinNode(n->left);
179         return n;
180     }
181     
182     BinaryTreeNode* findMaxNode(BinaryTreeNode *n)
183     {
184         if (n->right)
185             return findMaxNode(n->right);
186         return n;
187     }
188 
189     BinaryTreeNode* searchNode(Comparable d)
190     {
191         BinaryTreeNode *r = root;
192         while (r)
193         {
194             if (d < r->data)
195                 r = r->left;
196             else if (d > r->data)
197                 r = r->right;
198             else
199                 return r;
200         }
201         return NULL;
202     }
203     
204     BinaryTreeNode* findPredeNode(BinaryTreeNode *n)
205     {
206         BinaryTreeNode *p = NULL;
207         if (n->left)
208             return findMaxNode(n->left);
209         p = n->parent;
210         while (p && n == p->left)
211         {
212             n = p;
213             p = p->parent;
214         }
215         return p;
216     }
217     
218     BinaryTreeNode* findSucNode(BinaryTreeNode *n)
219     {
220         BinaryTreeNode *p = NULL;
221         if (n->right)
222             return findMinNode(n->right);
223         p = n->parent;
224         while (p && n == p->right)
225         {
226             n = p;
227             p = p->parent;
228         }
229         return p;
230     }
231     
232     void makeEmpty(BinaryTreeNode *&n) // 需要改变指针参数
233     {
234         if (n)
235         {
236             makeEmpty(n->left);
237             makeEmpty(n->right);
238             delete n;
239             n = NULL;
240         }
241         return;
242     }
243     
244     void insertNode(Comparable d, BinaryTreeNode *n)
245     {
246         if (d < n->data)
247         {
248             if (n->left)
249                 insertNode(d, n->left);
250             else
251             {
252                 n->left = new BinaryTreeNode(d);
253                 n->left->parent = n;
254             }
255             n->left->height = maxHeight(n->left);
256             if (height(n->left) - height(n->right) == 2)
257             {
258                 if (d < n->left->data)
259                     rotateWithLeftChild(n);
260                 else
261                     doubleRotateWithLeftChild(n);
262             }
263         }
264         else if (d > n->data)
265         {
266             if (n->right)
267                 insertNode(d, n->right);
268             else
269             {
270                 n->right = new BinaryTreeNode(d);
271                 n->right->parent = n;
272             }
273             n->right->height = maxHeight(n->right);
274             if (height(n->right) - height(n->left) == 2)
275             {
276                 if (d > n->right->data)
277                     rotateWithRightChild(n);
278                 else
279                     doubleRotateWithRightChild(n);
280             }
281         }
282         else
283             ;
284     }
285     
286     void removeNode(BinaryTreeNode *n)
287     {
288         if (!n)
289             return;
290         if (n->left && n->right)
291         {
292             //n->data = findPredeNode(n)->data;
293             //removeNode(findPredeNode(n));
294             n->data = findSucNode(n)->data;
295             removeNode(findSucNode(n));
296         }
297         else
298         {
299             BinaryTreeNode *x = (n->left) ? n->left : n->right;
300             if (n == root)
301                 root = x;
302             else
303             {
304                 BinaryTreeNode *p = n->parent;
305 
306                 if (n == p->left)
307                     p->left = x;
308                 else
309                     p->right = x;
310 
311                 delete n;
312                 n = NULL;
313                 if (x)
314                     x->parent = p;
315                 decreaseHeight(p);
316             }
317         }
318     }
319     
320     void printTree(BinaryTreeNode *r)
321     {
322         if (!r)
323             return;
324         printTree(r->left);
325         cout << r->data << "(" << r->height << ")" << " ";
326         printTree(r->right);
327     }
328     
329     int height(BinaryTreeNode *n)
330     {
331         return n ? n->height : -1;
332     }
333     
334     int maxHeight(BinaryTreeNode *n)
335     {
336         int lh = height(n->left);
337         int rh = height(n->right);
338         return lh > rh ? lh+1 : rh+1;
339     }
340     
341     void decreaseHeight(BinaryTreeNode *n)
342     {
343         if (n)
344         {
345             n->height = maxHeight(n);
346             
347             if ((height(n->left) - height(n->right)) == 2 )
348             {
349                 if (height(n->left->right) > height(n->left->left))
350                     doubleRotateWithLeftChild(n);
351                 else
352                     rotateWithLeftChild(n);
353             }
354             else if ((height(n->right) - height(n->left)) == 2)
355             {
356                 if (height(n->right->left) > height(n->right->right))
357                     doubleRotateWithRightChild(n);
358                 else
359                     rotateWithRightChild(n);
360             }
361             else
362                 ;
363             
364             decreaseHeight(n->parent);
365         }
366     }
367     
368     void rotateWithLeftChild(BinaryTreeNode *k2)
369     {
370         BinaryTreeNode *k1 = k2->left;
371         if (k1->right)
372             k1->right->parent = k2;
373         k2->left = k1->right;
374         k1->parent = k2->parent;
375         if (!k2->parent)
376             root = k1;
377         else if (k2 == k2->parent->left)
378             k2->parent->left = k1;
379         else if (k2 == k2->parent->right)
380             k2->parent->right = k1;
381         else
382             ;
383         k2->parent = k1;
384         k1->right = k2;
385         k1->height = maxHeight(k1);
386         k2->height = maxHeight(k2);
387     }
388     
389     void rotateWithRightChild(BinaryTreeNode *k1)
390     {
391         BinaryTreeNode *k2 = k1->right;
392         if (k2->left)
393             k2->left->parent = k1;
394         k1->right = k2->left;
395         k2->parent = k1->parent;
396         if (!k1->parent)
397             root = k2;
398         else if (k1 == k1->parent->left)
399             k1->parent->left = k2;
400         else if (k2 == k2->parent->right)
401             k1->parent->right = k2;
402         else
403             ;
404         k1->parent = k2;
405         k2->left = k1;
406         k1->height = maxHeight(k1);
407         k2->height = maxHeight(k2);
408     }
409     
410     void doubleRotateWithLeftChild(BinaryTreeNode *k3)
411     {
412         rotateWithRightChild(k3->left);
413         rotateWithLeftChild(k3);
414     }
415     
416     void doubleRotateWithRightChild(BinaryTreeNode *k1)
417     {
418         rotateWithLeftChild(k1->right);
419         rotateWithRightChild(k1);
420     }
421 };

4.2 main.cpp

  1 #include <ctime>
  2 #include <iostream>
  3 #include <cstdlib>
  4 
  5 #include "AvlTree.hpp"
  6 
  7 using namespace std;
  8 
  9 const int LENGTH = 9;
 10 
 11 void generateTree(AvlTree<int> *tree)
 12 {
 13     srand((unsigned int)time(NULL));
 14     int i = LENGTH;
 15     while(i--)
 16     {
 17         tree->insert(rand() % 100);
 18         tree->printTree();
 19     }
 20 }
 21 
 22 void checkDeepClone(AvlTree<int> *tree)
 23 {
 24     AvlTree<int> *newTree = tree;
 25     //AvlTree<int> *newTree = new AvlTree<int>(tree);
 26     cout << "数据拷贝完成" << endl;
 27     newTree->printTree();
 28 }
 29 
 30 void checkMinMax(AvlTree<int> *tree)
 31 {
 32     cout << "Min: " << tree->findMin() << endl;
 33     cout << "Max: " << tree->findMax() << endl;
 34 }
 35 
 36 void checkContains(AvlTree<int> *tree)
 37 {
 38     int elem;
 39     cout << "请输入用来测试是否包含的数据: ";
 40     cin >> elem;
 41     if (tree->contains(elem))
 42         cout << "存在" << endl;
 43     else
 44         cout << "不存在" << endl;
 45 }
 46 
 47 void checkPreSuc(AvlTree<int> *tree)
 48 {
 49     int elem;
 50     cout << "请输入用来测试前趋后继的数据: ";
 51     cin >> elem;
 52     cout << elem << "的前趋为" << tree->findPredecessor(elem) << endl;
 53     cout << elem << "的后继为" << tree->findSuccessor(elem) << endl;
 54 }
 55 
 56 void checkEmpty(AvlTree<int> *tree)
 57 {
 58     if (tree->isEmpty())
 59         cout << "树为空" << endl;
 60     else
 61         cout << "树不为空" << endl;
 62 
 63     tree->makeEmpty();
 64     tree->printTree();
 65 
 66     if (tree->isEmpty())
 67         cout << "树为空" << endl;
 68     else
 69         cout << "树不为空" << endl;
 70 }
 71 
 72 void checkRemove(AvlTree<int> *tree)
 73 {
 74     if (tree->isEmpty())
 75     {
 76         generateTree(tree);
 77         tree->printTree();
 78     }
 79     while (!tree->isEmpty())
 80     {
 81         int elem;
 82         cout << "请输入要移除的数据: ";
 83         cin >> elem;
 84         tree->remove(elem);
 85         tree->printTree();
 86 
 87     }
 88 }
 89 
 90 int main()
 91 {
 92     AvlTree<int> *tree = new AvlTree<int>(); 
 93     generateTree(tree);
 94     tree->printTree();
 95 
 96     //checkDeepClone(tree);
 97 
 98     checkMinMax(tree);
 99 
100     //checkContains(tree);
101     //checkContains(tree);
102 
103     //checkPreSuc(tree);
104     //checkPreSuc(tree);
105     //checkPreSuc(tree);
106     //checkPreSuc(tree);
107 
108     //checkEmpty(tree);
109 
110     checkRemove(tree);
111 
112     system("pause");
113 }

4.3 运行结果截图

 

posted @ 2015-07-14 14:55  yoleimei  阅读(1766)  评论(0编辑  收藏  举报