SplayTree伸展树的非递归实现(自底向上)
Splay Tree 是二叉查找树的一种,它与平衡二叉树、红黑树不同的是,Splay Tree从不强制地保持自身的平衡,每当查找到某个节点n的时候,在返回节点n的同时,Splay Tree会将节点n旋转到树根的位置,这样就使得Splay Tree天生有着一种类似缓存的能力,因为每次被查找到的节点都会被搬到树根的位置,所以当80%的情况下我们需要查找的元素都是某个固定的节点,或者是一部分特定的节点时,那么在很多时候,查找的效率会是O(1)的效率!当然如果查找的节点是很均匀地分布在不同的地方时,Splay Tree的性能就会变得很差了,但Splay Tree的期望的时间复杂度还是O(nlogn)的。
下图是对伸展树查询节点1和删除节点6的结果,利用我的伸展树来实现
1 头文件———————————————————————————— 2 #ifndef _SPLAY_TREE_H_ 3 #define _SPLAY_TREE_H_ 4 5 #include <iostream> 6 #include <iomanip> 7 #include <cassert> 8 #include <stack> 9 10 typedef struct splay_tree_node_t 11 { 12 int data; 13 struct splay_tree_node_t *left; 14 struct splay_tree_node_t *right; 15 } splay_tree_node, *position, *splay_tree; 16 17 void print_splay_tree(splay_tree st, int depth, int ctrl);//ctrl:0=root 1=left 2=right 18 position find_max(splay_tree st); 19 void insert_splay_tree(splay_tree *pst, int x); 20 void delete_splay_tree(splay_tree *pst, int x); 21 int find_splay_tree(splay_tree *pst, int x); 22 23 splay_tree rotate3(position child, position parent, position grand_parent, int *type); 24 splay_tree rotate2(position child, position parent); 25 26 inline void fcn(int type, position cur, position parent, position grand_parent); 27 #endif 28 29 源文件—————————————————————————————— 30 #include "./SplayTree.h" 31 32 splay_tree rotate3(position child, position parent, position grand_parent, int *type) 33 { 34 assert(child != NULL && parent != NULL && grand_parent != NULL); 35 36 if(parent->left == child && grand_parent->left == parent)//child, parent, grand_parent一字形东北方向 0 37 { 38 *type = 0; 39 grand_parent->left = parent->right; 40 parent->right = grand_parent; 41 42 parent->left = child->right; 43 child->right = parent; 44 } 45 else if(parent->right == child && grand_parent->right == parent)//child, parent, grand_parent一字形西北方向 1 46 { 47 *type = 1; 48 grand_parent->right = parent->left; 49 parent->left = grand_parent; 50 51 parent->right = child->left; 52 child->left = parent; 53 } 54 else if(parent->right == child && grand_parent->left == parent)//child, parent, grand_parent之字形< 55 { 56 *type = 2; 57 grand_parent->left = child->right; 58 parent->right = child->left; 59 child->left = parent; 60 child->right = grand_parent; 61 } 62 else if(parent->left == child && grand_parent->right == parent)//child, parent, grand_parent之字形> 63 { 64 *type = 3; 65 grand_parent->right = child->left; 66 parent->left = child->right; 67 child->right = parent; 68 child->left - grand_parent; 69 } 70 71 return child; 72 } 73 splay_tree rotate2(position child, position parent) 74 { 75 assert(child != NULL && parent != NULL); 76 if(parent->left == child) 77 { 78 parent->left = child->right; 79 child->right = parent; 80 } 81 else//parent->right == child 82 { 83 parent->right = child->left; 84 child->left = parent; 85 } 86 return child; 87 } 88 89 position find_max(splay_tree st) 90 { 91 while(NULL != st && NULL != st->right) 92 st = st->right; 93 return st; 94 } 95 96 void print_splay_tree(splay_tree st, int depth, int ctrl) 97 { 98 if(NULL != st) 99 { 100 std::cout<<std::setw(depth); 101 if(0 == ctrl) 102 std::cout<<"root:"; 103 else if(1 == ctrl) 104 std::cout<<"left"; 105 else if(2 == ctrl) 106 std::cout<<"right"; 107 std::cout<<st->data<<std::endl; 108 print_splay_tree(st->left, depth+6, 1); 109 print_splay_tree(st->right, depth+6, 2); 110 } 111 } 112 void insert_splay_tree(splay_tree *pst, int x) 113 { 114 if(NULL == *pst) 115 { 116 position tmp = new splay_tree_node; 117 if(NULL == tmp) 118 return ; 119 tmp->data = x; 120 tmp->left = tmp->right = NULL; 121 *pst = tmp; 122 } 123 else if(x < (*pst)->data) 124 insert_splay_tree(&((*pst)->left), x); 125 else if(x > (*pst)->data) 126 insert_splay_tree(&((*pst)->right), x); 127 else 128 return ; 129 } 130 void delete_splay_tree(splay_tree *pst, int x) 131 { 132 assert(NULL != pst); 133 int res = find_splay_tree(pst, x); 134 if(res == 0)//not found 135 return ; 136 //此时root指向的就是要删除的节点,因为find_splay_tree操作将节点推至向根 137 position root = *pst; 138 splay_tree splay_left = root->left; 139 splay_tree splay_right = root->right; 140 position tmp = find_max(splay_left); 141 if(NULL == tmp)//无左子树 142 *pst = splay_right;//将右子树为新树 143 else 144 { 145 find_splay_tree(&splay_left, tmp->data); 146 splay_left->right = splay_right;//将右子树为左子树的新右子树 147 *pst = splay_left;//将左子树为新树 148 } 149 } 150 int find_splay_tree(splay_tree *pst, int x) 151 { 152 assert(NULL != pst); 153 position cur = *pst; 154 std::stack<position> s; 155 156 while(cur != NULL && cur->data != x)//沿着查找路径将树节点以此压入栈中 157 { 158 if(x < cur->data) 159 { 160 s.push(cur); 161 cur = cur->left; 162 } 163 else 164 { 165 s.push(cur); 166 cur = cur->right; 167 } 168 } 169 170 if(NULL == cur)//not found 171 return false; 172 173 position parent, grand_parent; 174 int type = -1;//0一字形东北方向; 1一字形西北方向; 2之字形<; 3之字形< 175 //每次取父节点和祖父节点和当前节点进行伸展调节 176 while(s.size() >= 2) 177 { 178 parent = s.top(); 179 s.pop(); 180 //fcn判断伸展的类型以便重新调整原来的树指针,调整好了才可以再次伸展 181 fcn(type, cur, parent, grand_parent); 182 grand_parent = s.top(); 183 s.pop(); 184 cur = rotate3(cur, parent, grand_parent, &type);//after rotate, cur is the new "root" 185 } 186 if(s.empty()) 187 *pst = cur; 188 else //rotate cur and the old root 189 { 190 parent = s.top(); 191 s.pop(); 192 fcn(type, cur, parent, grand_parent); 193 //此时只对cur和根节点进行伸展,完成后find_splay_tree函数结束 194 *pst = rotate2(cur, parent); 195 } 196 197 return true; 198 } 199 200 //fcn判断伸展的类型以便重新调整原来的树指针,调整好了才可以再次伸展 201 inline void fcn(int type, position cur, position parent, position grand_parent) 202 { 203 if(type == 0) 204 { 205 if(grand_parent == parent->left) 206 parent->left = cur; 207 else if(grand_parent == parent->right) 208 parent->right = cur; 209 } 210 else if(type == 1) 211 { 212 if(grand_parent == parent->left) 213 parent->left = cur; 214 else if(grand_parent == parent->right) 215 parent->right = cur; 216 } 217 else if(type == 2) 218 { 219 if(grand_parent == parent->left) 220 parent->left = cur; 221 else if(grand_parent == parent->right) 222 parent->right = cur; 223 } 224 else if(type == 3) 225 { 226 if(grand_parent == parent->left) 227 parent->left = cur; 228 else if(grand_parent == parent->right) 229 parent->right = cur; 230 } 231 }