首页 > 代码库 > 《数据结构与算法分析:C语言描述》复习——第四章“树”——AVL树
《数据结构与算法分析: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 // X345 // / 346 // Y C347 // / 348 // A B349 // ----------350 // After rotation:351 // Y352 // / 353 // A X354 // / 355 // B C356 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 // X389 // / 390 // A Y391 // / 392 // B C393 // ----------394 // After rotation:395 // Y396 // / 397 // X C398 // / 399 // A B400 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 // X433 // / 434 // Y D435 // / 436 // A Z437 // / 438 // B C439 // ----------440 // After rotation:441 // Z442 // / 443 // Y X444 // / \ / 445 // A B C D446 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 // X488 // / 489 // A Y490 // / 491 // Z D492 // / 493 // B C494 // ----------495 // After rotation:496 // Z497 // / 498 // X Y499 // / \ / 500 // A B C D501 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 rotation545 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 rotation566 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, left576 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, right594 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 }