首页 > 代码库 > 《数据结构与算法分析:C语言描述》复习——第四章“树”——伸展树

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

2014.06.15 20:42

简介:

  伸展树是一种介于普通二叉搜索树和AVL树之间的,比较平衡的一种二叉搜索树。它不像AVL树那样总是高度平衡,虽然单次操作的就可能耗费O(n)时间,但连续M次基本操作的时间复杂度能做到O(M * log(N)),M当然不能和1太接近。这种复杂度叫做均摊复杂度,英文叫amortiized complexity。当我学这门课的时候,这个概念我根本不理解,伸展树我也没有动手写过。后来在多个编程题目中的算法分析中,逐渐明白了均摊复杂度的意义。伸展树的一大特点,就是每次要访问一个节点,一定要想办法把它弄到根节点。这个办法,就是“旋转”。如果你明白AVL树的旋转,这个自然也不必多说了。不过,伸展树除了左单旋转、右单旋转、左右双旋转、右左双旋转之外,还用到了左左双旋转,右右双旋转。AVL旋转是为了恢复树的平衡,伸展树的旋转则是为了把一个节点一直旋转到根节点。在我费劲力气实现了AVL树之后,我以为能通过删掉很多代码把它变成伸展树,结果除了不再记录树的高度之外,我没删掉多少代码,还额外增加了两个旋转。事实证明伸展树也是个好想但不好写的结构。

图示:

  照理说增删改查都应该给出图示,但我只想用图示说明一个节点是如何被旋转到根节点的。旋转不是为了恢复平衡,但旋转的确可以让一棵树变得更平衡,这也是伸展树高效率的关键——越旋转越平衡。

  

实现:

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