《数据结构与算法分析:C语言描述》复习——第四章“树”——AVL树

2014.06.15 16:22

简介:

  AVL树是一种高度平衡的二叉搜索树,其命名源自于联合发明算法的三位科学家的名字的首字母。此处“平衡”的定义是:任意节点的左右子树的高度相差不超过1。有了这个平衡的性质,使得AVL树的高度H总是接近log(N),因此各种增删改查的操作的复杂度能够保证在对数级别。没有bad case是AVL树与普通的二叉搜索树的最大区别。为了实现平衡性质,我们需要记录每个节点的高度(或者平衡因子)来检测不平衡的情况。为了修正高度不平衡,需要用到“旋转”的方法,分为单旋转和双旋转,左右总共四种旋转。下面的图解会给出旋转的示意,这个是AVL树的关键算法。AVL树看起来特简单,但你动手写写就知实现一棵AVL树有多麻烦。如果你能用200行写出能增删改查的AVL树,请留言给我点提示。我花了一天想思路,并犹豫要不要放弃。又花了一天写代码和自测。终于用500多行代码写完了自己的第一棵AVL树。如果面试里需要平衡查找结构,你最好试试树堆或者跳表,千万别想AVL或者伸展树。不需要自己写的话,还是<map>吧。

图示:

  一棵平衡的二叉树:

  

  查找不涉及数据的修改,因此和普通二叉搜索树完全一样:

    

  插入21之后,树的平衡被破坏了,而且不止一个点出现了不平衡:

  

  当平衡被破坏之后,需要从第一个不平衡的地方开始旋转,然后逐层往上继续修正。此处给出一次旋转之后的结果:

  

  一次旋转不一定能修复N个不平衡的节点,因此要从第一个不平衡的节点往上检查所有需要修复的节点。

  下面给出四种旋转的示意图,代码的注释中也有类似的示意,以便读者能够直观地想象旋转中发生的变形(数据结构最大的魅力,就在于它们动起来比变形金刚的花样还多)。

  左单旋转:

  

  右单旋转:

  

  左右双旋转:

  

  右左双旋转:

  

实现:

  为了向上检查,我引入了parent指针指向二叉树节点的父节点。为了检查平衡状况,我是用了height成员表示树的高度。虽然平衡因子好像更规范,但当时尝试用平衡因子的时候思路始终理不清楚,所以选择了高度作为依据。下面的实现中其实有不少代码是供测试用的,比如三种遍历。这些debug代码对于学习AVL树有帮助作用,如果你有兴趣可以自己运行查看结果。

  插入和删除都会影响树的平衡性,因此对于发生变动的节点,需要更新其高度,以便检测平衡性并进行旋转。AVL树的删除挺难想的,需要在草稿纸上比划半天才能想明白。

  请看代码。

  1 // My implementation for avl tree.
  2 #include <iostream>
  3 #include <string>
  4 #include <vector>
  5 using namespace std;
  6 
  7 struct TreeNode {
  8     int val;
  9     int height;
 10     TreeNode *left;
 11     TreeNode *right;
 12     TreeNode *parent;
 13     TreeNode(int _val): val(_val), height(1), left(nullptr), right(nullptr), parent(nullptr) {};
 14 };
 15 
 16 class AVLTree {
 17 public:
 18     AVLTree() {
 19         m_root = nullptr;
 20     }
 21     
 22     bool empty() {
 23         return m_root == nullptr;
 24     }
 25     
 26     void clear() {
 27         _deleteTree(m_root);
 28     }
 29     
 30     void insertNode(const int &val) {
 31         if (m_root == nullptr) {
 32             m_root = new TreeNode(val);
 33             return;
 34         }
 35 
 36         TreeNode *ptr = _findNode(val);
 37         
 38         if (val == ptr->val) {
 39             return;
 40         }
 41         
 42         if (val < ptr->val) {
 43             ptr->left = new TreeNode(val);
 44             ptr->left->parent = ptr;
 45         } else if (val > ptr->val) {
 46             ptr->right = new TreeNode(val);
 47             ptr->right->parent = ptr;
 48         }
 49         
 50         int hl, hr;
 51         TreeNode *ptr2;
 52         while (ptr != nullptr) {
 53             ptr2 = ptr->parent;
 54             _getHeight(ptr);
 55             hl = _height(ptr->left);
 56             hr = _height(ptr->right);
 57             switch(hl - hr) {
 58             case -2:
 59                 switch (_height(ptr->right->left) - _height(ptr->right->right)) {
 60                 case -1:
 61                     _singleRotationRight(ptr);
 62                     break;
 63                 case +1:
 64                     _doubleRotationRightLeft(ptr);
 65                     break;
 66                 }
 67                 break;
 68             case +2:
 69                 switch (_height(ptr->left->left) - _height(ptr->left->right)) {
 70                 case -1:
 71                     _doubleRotationLeftRight(ptr);
 72                     break;
 73                 case +1:
 74                     _singleRotationLeft(ptr);
 75                     break;
 76                 }
 77                 break;
 78             }
 79             ptr = ptr2;
 80         }
 81     }
 82     
 83     void deleteNode(const int &val) {
 84         if (m_root == nullptr) {
 85             return;
 86         }
 87         
 88         TreeNode *par, *cur;
 89         
 90         cur = _findNode(val);
 91         if (cur == nullptr || cur->val != val) {
 92             return;
 93         }
 94         par = cur->parent;
 95         
 96         TreeNode *ptr;
 97         do {
 98             if (cur->left != nullptr) {
 99                 ptr = _shiftLeft(cur);
100                 break;
101             }
102         
103             if (cur->right != nullptr) {
104                 ptr = _shiftRight(cur);
105                 break;
106             }
107         
108             if (par == nullptr) {
109                 delete cur;
110                 m_root = nullptr;
111             } else if (val < par->val) {
112                 delete cur;
113                 par->left = nullptr;
114             } else {
115                 delete cur;
116                 par->right = nullptr;
117             }
118             ptr = par;
119         } while (0);
120 
121         int hl, hr;
122         TreeNode *ptr2;
123         while (ptr != nullptr) {
124             ptr2 = ptr->parent;
125             _getHeight(ptr);
126             hl = _height(ptr->left);
127             hr = _height(ptr->right);
128             switch(hl - hr) {
129             case -2:
130                 switch (_height(ptr->right->left) - _height(ptr->right->right)) {
131                 case -1:
132                     _singleRotationRight(ptr);
133                     break;
134                 case +1:
135                     _doubleRotationRightLeft(ptr);
136                     break;
137                 }
138                 break;
139             case +2:
140                 switch (_height(ptr->left->left) - _height(ptr->left->right)) {
141                 case -1:
142                     _doubleRotationLeftRight(ptr);
143                     break;
144                 case +1:
145                     _singleRotationLeft(ptr);
146                     break;
147                 }
148                 break;
149             }
150             ptr = ptr2;
151         }
152     }
153     
154     void updateNode(const int &old_val, const int &new_val) {
155         deleteNode(old_val);
156         insertNode(new_val);
157     }
158     
159     bool contains(const int &val) {
160         TreeNode *ptr = _findNode(val);
161         return ptr == nullptr ? false : ptr->val == val ? true : false;
162     }
163     
164     string preorderTraversal() {
165         string result;
166         _preorderTraversalRecursive(m_root, result);
167         return result;
168     }
169     
170     string inorderTraversal() {
171         string result;
172         _inorderTraversalRecursive(m_root, result);
173         return result;
174     }
175     
176     string postorderTraversal() {
177         string result;
178         _postorderTraversalRecursive(m_root, result);
179         return result;
180     }
181     
182     ~AVLTree() {
183         clear();
184     }
185 private:
186     TreeNode *m_root;
187     
188     void _deleteTree(TreeNode *&root) {
189         if (root == nullptr) {
190             return;
191         }
192         _deleteTree(root->left);
193         _deleteTree(root->right);
194         delete root;
195         root = nullptr;
196     }
197     
198     TreeNode* _findNode(const int &val) {
199         TreeNode *ptr;
200         
201         ptr = m_root;
202         while (ptr != nullptr) {
203             if (val == ptr->val) {
204                 return ptr;
205             }
206             if (val < ptr->val) {
207                 if (ptr->left != nullptr) {
208                     ptr = ptr->left;
209                 } else {
210                     return ptr;
211                 }
212             } else {
213                 if (ptr->right != nullptr) {
214                     ptr = ptr->right;
215                 } else {
216                     return ptr;
217                 }
218             }
219         }
220         return ptr;
221     }
222     
223     void _preorderTraversalRecursive(const TreeNode  *root, string &result) {
224         result.push_back('{');
225         if (root == nullptr) {
226             // '#' represents NULL.
227             result.push_back('#');
228         } else {
229             result.append(to_string(root->val));
230             _preorderTraversalRecursive(root->left, result);
231             _preorderTraversalRecursive(root->right, result);
232         }
233         result.push_back('}');
234     }
235     
236     void _inorderTraversalRecursive(const TreeNode  *root, string &result) {
237         result.push_back('{');
238         if (root == nullptr) {
239             // '#' represents NULL.
240             result.push_back('#');
241         } else {
242             _inorderTraversalRecursive(root->left, result);
243             result.append(to_string(root->val));
244             _inorderTraversalRecursive(root->right, result);
245         }
246         result.push_back('}');
247     }
248     
249     void _postorderTraversalRecursive(const TreeNode  *root, string &result) {
250         result.push_back('{');
251         if (root == nullptr) {
252             // '#' represents NULL.
253             result.push_back('#');
254         } else {
255             _postorderTraversalRecursive(root->left, result);
256             _postorderTraversalRecursive(root->right, result);
257             result.append(to_string(root->val));
258         }
259         result.push_back('}');
260     }
261     
262     TreeNode *_shiftLeft(TreeNode *root) {
263         TreeNode *cur, *par;
264         
265         // root and root->left is guaranteed to be non-empty.
266         par = root;
267         cur = par->left;
268         
269         while (cur->right != nullptr) {
270             par = cur;
271             cur = cur->right;
272         }
273         root->val = cur->val;
274         
275         if (cur->left != nullptr) {
276             return _shiftLeft(cur);
277         }
278         
279         if (cur->right != nullptr) {
280             return _shiftRight(cur);
281         }
282         
283         if (cur == par->left) {
284             delete par->left;
285             par->left = nullptr;
286         } else {
287             delete par->right;
288             par->right = nullptr;
289         }
290 
291         return par;
292     }
293 
294     TreeNode *_shiftRight(TreeNode *root) {
295         TreeNode *cur, *par;
296         
297         // root and root->right is guaranteed to be non-empty.
298         par = root;
299         cur = par->right;
300         
301         while (cur->left != nullptr) {
302             par = cur;
303             cur = cur->left;
304         }
305         root->val = cur->val;
306         
307         if (cur->left != nullptr) {
308             return _shiftLeft(cur);
309         }
310         
311         if (cur->right != nullptr) {
312             return _shiftRight(cur);
313         }
314         
315         if (cur == par->left) {
316             delete par->left;
317             par->left = nullptr;
318         } else {
319             delete par->right;
320             par->right = nullptr;
321         }
322         
323         return par;
324     }
325     
326     int _max(const int &x, const int &y) {
327         return x > y ? x : y;
328     }
329     
330     int _height(const TreeNode *ptr) {
331         return ptr == nullptr ? 0 : ptr->height;
332     }
333     
334     void _getHeight(TreeNode *ptr) {
335         if (ptr == nullptr) {
336             return;
337         }
338         ptr->height = _max(_height(ptr->left), _height(ptr->right)) + 1;
339     }
340     
341     void _singleRotationLeft(TreeNode *cur) {
342         // Subtree A is deeper than subtree B.
343         // Before rotation:
344         //     X
345         //    / \
346         //   Y   C
347         //  / \
348         // A   B
349         // ----------
350         // After rotation:
351         //   Y
352         //  / \
353         // A   X
354         //    / \
355         //   B   C
356         TreeNode *par = cur->parent;
357         TreeNode *B;
358         TreeNode *X, *Y;
359         
360         X = cur;
361         Y = cur->left;
362         B = Y->right;
363         
364         Y->right = X;
365         X->parent = Y;
366         X->left = B;
367         if (B != nullptr) {
368             B->parent = Y;
369         }
370         
371         if (par == nullptr) {
372             m_root = Y;
373         } else if (par->left == cur) {
374             par->left = Y;
375         } else {
376             par->right = Y;
377         }
378         Y->parent = par;
379         
380         _getHeight(X);
381         _getHeight(Y);
382         _getHeight(par);
383     }
384     
385     void _singleRotationRight(TreeNode *cur) {
386         // Subtree C is deeper than subtree B.
387         // Before rotation:
388         //   X
389         //  / \
390         // A   Y
391         //    / \
392         //   B   C
393         // ----------
394         // After rotation:
395         //     Y
396         //    / \
397         //   X   C
398         //  / \
399         // A   B
400         TreeNode *par = cur->parent;
401         TreeNode *B;
402         TreeNode *X, *Y;
403         
404         X = cur;
405         Y = cur->right;
406         B = Y->left;
407         
408         Y->left = X;
409         X->parent = Y;
410         X->right = B;
411         if (B != nullptr) {
412             B->parent = X;
413         }
414         
415         if (par == nullptr) {
416             m_root = Y;
417         } else if (par->left == cur) {
418             par->left = Y;
419         } else {
420             par->right = Y;
421         }
422         Y->parent = par;
423         
424         _getHeight(X);
425         _getHeight(Y);
426         _getHeight(par);
427     }
428     
429     void _doubleRotationLeftRight(TreeNode *cur) {
430         // Subtree Z is deeper than subtree A. Single rotation won't work, so let's use this one instead.
431         // Before rotation:
432         //     X
433         //    / \
434         //   Y   D
435         //  / \
436         // A   Z
437         //    / \
438         //   B   C
439         // ----------
440         // After rotation:
441         //      Z
442         //    /   \
443         //   Y     X
444         //  / \   / \
445         // A   B C   D
446         TreeNode *par = cur->parent;
447         TreeNode *B, *C;
448         TreeNode *X, *Y, *Z;
449         
450         X = cur;
451         Y = X->left;
452         Z = Y->right;
453         B = Z->left;
454         C = Z->right;
455         
456         Z->left = Y;
457         Y->parent = Z;
458         Z->right = X;
459         X->parent = Z;
460         Y->right = B;
461         if (B != nullptr) {
462             B->parent = X;
463         }
464         X->left = C;
465         if (C != nullptr) {
466             C->parent = X;
467         }
468         
469         if (par == nullptr) {
470             m_root = Z;
471         } else if (par->left == cur) {
472             par->left = Z;
473         } else {
474             par->right = Z;
475         }
476         Z->parent = par;
477         
478         _getHeight(X);
479         _getHeight(Y);
480         _getHeight(Z);
481         _getHeight(par);
482     }
483     
484     void _doubleRotationRightLeft(TreeNode *cur) {
485         // Subtree Z is deeper than subtree D. Single rotation won't work, so let's use this one instead.
486         // Before rotation:
487         //   X
488         //  / \
489         // A   Y
490         //    / \
491         //   Z   D
492         //  / \
493         // B   C
494         // ----------
495         // After rotation:
496         //      Z
497         //    /   \
498         //   X     Y
499         //  / \   / \
500         // A   B C   D
501         TreeNode *par = cur->parent;
502         TreeNode *B, *C;
503         TreeNode *X, *Y, *Z;
504         
505         X = cur;
506         Y = X->right;
507         Z = Y->left;
508         B = Z->left;
509         C = Z->right;
510         
511         Z->left = X;
512         X->parent = Z;
513         Z->right = Y;
514         Y->parent = Z;
515         X->right = B;
516         if (B != nullptr) {
517             B->parent = X;
518         }
519         Y->left = C;
520         if (C != nullptr) {
521             C->parent = Y;
522         }
523         
524         if (par == nullptr) {
525             m_root = Z;
526         } else if (par->left == cur) {
527             par->left = Z;
528         } else {
529             par->right = Z;
530         }
531         Z->parent = par;
532         
533         _getHeight(X);
534         _getHeight(Y);
535         _getHeight(Z);
536         _getHeight(par);
537     }
538 };
539 
540 int main()
541 {
542     AVLTree avl;
543     
544     // test for single rotation
545     avl.insertNode(1);
546     cout << avl.preorderTraversal() << endl;
547     avl.insertNode(2);
548     cout << avl.preorderTraversal() << endl;
549     avl.insertNode(3);
550     cout << avl.preorderTraversal() << endl;
551     avl.insertNode(4);
552     cout << avl.preorderTraversal() << endl;
553     avl.insertNode(5);
554     cout << avl.preorderTraversal() << endl;
555     avl.insertNode(6);
556     cout << avl.preorderTraversal() << endl;
557     avl.insertNode(7);
558     cout << avl.preorderTraversal() << endl;
559     avl.insertNode(8);
560     cout << avl.preorderTraversal() << endl;
561     avl.insertNode(9);
562     cout << avl.preorderTraversal() << endl;
563     cout << endl;
564 
565     // test for double rotation
566     avl.clear();
567     avl.insertNode(3);
568     cout << avl.preorderTraversal() << endl;
569     avl.insertNode(1);
570     cout << avl.preorderTraversal() << endl;
571     avl.insertNode(2);
572     cout << avl.preorderTraversal() << endl;
573     cout << endl;
574 
575     // test for deletion, left
576     avl.clear();
577     avl.insertNode(3);
578     cout << avl.preorderTraversal() << endl;
579     avl.insertNode(2);
580     cout << avl.preorderTraversal() << endl;
581     avl.insertNode(4);
582     cout << avl.preorderTraversal() << endl;
583     avl.insertNode(1);
584     cout << avl.preorderTraversal() << endl;
585     avl.deleteNode(3);
586     cout << avl.preorderTraversal() << endl;
587     avl.deleteNode(2);
588     cout << avl.preorderTraversal() << endl;
589     avl.deleteNode(4);
590     cout << avl.preorderTraversal() << endl;
591     cout << endl;
592     
593     // test for deletion, right
594     avl.clear();
595     avl.insertNode(2);
596     cout << avl.preorderTraversal() << endl;
597     avl.insertNode(1);
598     cout << avl.preorderTraversal() << endl;
599     avl.insertNode(3);
600     cout << avl.preorderTraversal() << endl;
601     avl.insertNode(4);
602     cout << avl.preorderTraversal() << endl;
603     avl.deleteNode(2);
604     cout << avl.preorderTraversal() << endl;
605     avl.deleteNode(1);
606     cout << avl.preorderTraversal() << endl;
607     avl.deleteNode(3);
608     cout << avl.preorderTraversal() << endl;
609     cout << endl;
610 
611     return 0;
612 }

 

转载于:https://www.cnblogs.com/zhuli19901106/p/3789679.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值