概要
上一章介绍了伸展树的基本概念,并通过C语言实现了伸展树。本章是伸展树的C++实现,后续再给出Java版本。还是那句老话,它们的原理都一样,择其一了解即可。
目录
1. 伸展树的介绍
2. 伸展树的C++实现(完整源码)
3. 伸展树的C++测试程序
转载请注明出处:http://www.cnblogs.com/skywang12345/p/3604258.html
更多内容: 数据结构与算法系列 目录
(01) 伸展树(一)之 图文解析 和 C语言的实现
(02) 伸展树(二)之 C++的实现
(03) 伸展树(三)之 Java的实现
伸展树的介绍
伸展树(Splay Tree)是特殊的二叉查找树。
它的特殊是指,它除了本身是棵二叉查找树之外,它还具备一个特点: 当某个节点被访问时,伸展树会通过旋转使该节点成为树根。这样做的好处是,下次要访问该节点时,能够迅速的访问到该节点。
伸展树的C++实现
1. 基本定义
1.1 节点
template <class T> class SplayTreeNode{ public: T key; // 关键字(键值) SplayTreeNode *left; // 左孩子 SplayTreeNode *right; // 右孩子 SplayTreeNode():left(NULL),right(NULL) {} SplayTreeNode(T value, SplayTreeNode *l, SplayTreeNode *r): key(value), left(l),right(r) {} };
SplayTreeNode是伸展树节点对应的类。它包括的几个组成元素:
(01) key -- 是关键字,是用来对伸展树的节点进行排序的。
(02) left -- 是左孩子。
(03) right -- 是右孩子。
1.2 伸展树
template <class T> class SplayTree { private: SplayTreeNode<T> *mRoot; // 根结点 public: SplayTree(); ~SplayTree(); // 前序遍历"伸展树" void preOrder(); // 中序遍历"伸展树" void inOrder(); // 后序遍历"伸展树" void postOrder(); // (递归实现)查找"伸展树"中键值为key的节点 SplayTreeNode<T>* search(T key); // (非递归实现)查找"伸展树"中键值为key的节点 SplayTreeNode<T>* iterativeSearch(T key); // 查找最小结点:返回最小结点的键值。 T minimum(); // 查找最大结点:返回最大结点的键值。 T maximum(); // 旋转key对应的节点为根节点,并返回值为根节点。 void splay(T key); // 将结点(key为节点键值)插入到伸展树中 void insert(T key); // 删除结点(key为节点键值) void remove(T key); // 销毁伸展树 void destroy(); // 打印伸展树 void print(); private: // 前序遍历"伸展树" void preOrder(SplayTreeNode<T>* tree) const; // 中序遍历"伸展树" void inOrder(SplayTreeNode<T>* tree) const; // 后序遍历"伸展树" void postOrder(SplayTreeNode<T>* tree) const; // (递归实现)查找"伸展树x"中键值为key的节点 SplayTreeNode<T>* search(SplayTreeNode<T>* x, T key) const; // (非递归实现)查找"伸展树x"中键值为key的节点 SplayTreeNode<T>* iterativeSearch(SplayTreeNode<T>* x, T key) const; // 查找最小结点:返回tree为根结点的伸展树的最小结点。 SplayTreeNode<T>* minimum(SplayTreeNode<T>* tree); // 查找最大结点:返回tree为根结点的伸展树的最大结点。 SplayTreeNode<T>* maximum(SplayTreeNode<T>* tree); // 旋转key对应的节点为根节点,并返回值为根节点。 SplayTreeNode<T>* splay(SplayTreeNode<T>* tree, T key); // 将结点(z)插入到伸展树(tree)中 SplayTreeNode<T>* insert(SplayTreeNode<T>* &tree, SplayTreeNode<T>* z); // 删除伸展树(tree)中的结点(键值为key),并返回被删除的结点 SplayTreeNode<T>* remove(SplayTreeNode<T>* &tree, T key); // 销毁伸展树 void destroy(SplayTreeNode<T>* &tree); // 打印伸展树 void print(SplayTreeNode<T>* tree, T key, int direction); };
SplayTree是伸展树对应的类。它包括根节点mRoot和伸展树的函数接口。
2. 旋转
旋转是伸展树中需要重点关注的,它的代码如下:
/* * 旋转key对应的节点为根节点,并返回值为根节点。 * * 注意: * (a):伸展树中存在"键值为key的节点"。 * 将"键值为key的节点"旋转为根节点。 * (b):伸展树中不存在"键值为key的节点",并且key < tree->key。 * b-1 "键值为key的节点"的前驱节点存在的话,将"键值为key的节点"的前驱节点旋转为根节点。 * b-2 "键值为key的节点"的前驱节点存在的话,则意味着,key比树中任何键值都小,那么此时,将最小节点旋转为根节点。 * (c):伸展树中不存在"键值为key的节点",并且key > tree->key。 * c-1 "键值为key的节点"的后继节点存在的话,将"键值为key的节点"的后继节点旋转为根节点。 * c-2 "键值为key的节点"的后继节点不存在的话,则意味着,key比树中任何键值都大,那么此时,将最大节点旋转为根节点。 */ template <class T> SplayTreeNode<T>* SplayTree<T>::splay(SplayTreeNode<T>* tree, T key) { SplayTreeNode<T> N, *l, *r, *c; if (tree == NULL) return tree; N.left = N.right = NULL; l = r = &N; for (;;) { if (key < tree->key) { if (tree->left == NULL) break; if (key < tree->left->key) { c = tree->left; /* rotate right */ tree->left = c->right; c->right = tree; tree = c; if (tree->left == NULL) break; } r->left = tree; /* link right */ r = tree; tree = tree->left; } else if (key > tree->key) { if (tree->right == NULL) break; if (key > tree->right->key) { c = tree->right; /* rotate left */ tree->right = c->left; c->left = tree; tree = c; if (tree->right == NULL) break; } l->right = tree; /* link left */ l = tree; tree = tree->right; } else { break; } } l->right = tree->left; /* assemble */ r->left = tree->right; tree->left = N.right; tree->right = N.left; return tree; } template <class T> void SplayTree<T>::splay(T key) { mRoot = splay(mRoot, key); }
上面的代码的作用:将"键值为key的节点"旋转为根节点,并返回根节点。它的处理情况共包括:
(a):伸展树中存在"键值为key的节点"。
将"键值为key的节点"旋转为根节点。
(b):伸展树中不存在"键值为key的节点",并且key < tree->key。
b-1) "键值为key的节点"的前驱节点存在的话,将"键值为key的节点"的前驱节点旋转为根节点。
b-2) "键值为key的节点"的前驱节点存在的话,则意味着,key比树中任何键值都小,那么此时,将最小节点旋转为根节点。
(c):伸展树中不存在"键值为key的节点",并且key > tree->key。
c-1) "键值为key的节点"的后继节点存在的话,将"键值为key的节点"的后继节点旋转为根节点。
c-2) "键值为key的节点"的后继节点不存在的话,则意味着,key比树中任何键值都大,那么此时,将最大节点旋转为根节点。
下面列举个例子分别对a进行说明。
在下面的伸展树中查找10,共包括"右旋" --> "右链接" --> "组合"这3步。
(01) 右旋
对应代码中的"rotate right"部分
(02) 右链接
对应代码中的"link right"部分
(03) 组合
对应代码中的"assemble"部分
提示:如果在上面的伸展树中查找"70",则正好与"示例1"对称,而对应的操作则分别是"rotate left", "link left"和"assemble"。
其它的情况,例如"查找15是b-1的情况,查找5是b-2的情况"等等,这些都比较简单,大家可以自己分析。
3. 插入
插入代码
/* * 将结点插入到伸展树中,并返回根节点 * * 参数说明: * tree 伸展树的根结点 * key 插入的结点的键值 * 返回值: * 根节点 */ template <class T> SplayTreeNode<T>* SplayTree<T>::insert(SplayTreeNode<T>* &tree, SplayTreeNode<T>* z) { SplayTreeNode<T> *y = NULL; SplayTreeNode<T> *x = tree; // 查找z的插入位置 while (x != NULL) { y = x; if (z->key < x->key) x = x->left; else if (z->key > x->key) x = x->right; else { cout << "不允许插入相同节点(" << z->key << ")!" << endl; delete z; return tree; } } if (y==NULL) tree = z; else if (z->key < y->key) y->left = z; else y->right = z; return tree; } template <class T> void SplayTree<T>::insert(T key) { SplayTreeNode<T> *z=NULL; // 如果新建结点失败,则返回。 if ((z=new SplayTreeNode<T>(key,NULL,NULL)) == NULL) return ; // 插入节点 mRoot = insert(mRoot, z); // 将节点(key)旋转为根节点 mRoot = splay(mRoot, key); }
insert(key)是提供给外部的接口,它的作用是新建节点(节点的键值为key),并将节点插入到伸展树中;然后,将该节点旋转为根节点。
insert(tree, z)是内部接口,它的作用是将节点z插入到tree中。insert(tree, z)在将z插入到tree中时,仅仅只将tree当作是一棵二叉查找树,而且不允许插入相同节点。
4. 删除
删除代码
/* * 删除结点(节点的键值为key),返回根节点 * * 参数说明: * tree 伸展树的根结点 * key 待删除结点的键值 * 返回值: * 根节点 */ template <class T> SplayTreeNode<T>* SplayTree<T>::remove(SplayTreeNode<T>* &tree, T key) { SplayTreeNode<T> *x; if (tree == NULL) return NULL; // 查找键值为key的节点,找不到的话直接返回。 if (search(tree, key) == NULL) return tree; // 将key对应的节点旋转为根节点。 tree = splay(tree, key); if (tree->left != NULL) { // 将"tree的前驱节点"旋转为根节点 x = splay(tree->left, key); // 移除tree节点 x->right = tree->right; } else x = tree->right; delete tree; return x; } template <class T> void SplayTree<T>::remove(T key) { mRoot = remove(mRoot, key); }
remove(key)是外部接口,remove(tree, key)是内部接口。
remove(tree, key)的作用是:删除伸展树中键值为key的节点。
它会先在伸展树中查找键值为key的节点。若没有找到的话,则直接返回。若找到的话,则将该节点旋转为根节点,然后再删除该节点。
注意:关于伸展树的"前序遍历"、"中序遍历"、"后序遍历"、"最大值"、"最小值"、"查找"、"打印"、"销毁"等接口与"二叉查找树"基本一样,这些操作在"二叉查找树"中已经介绍过了,这里就不再单独介绍了。当然,后文给出的伸展树的完整源码中,有给出这些API的实现代码。这些接口很简单,Please RTFSC(Read The Fucking Source Code)!
伸展树的C++实现(完整源码)
伸展树的实现文件(SplayTree.h)
1 #ifndef _SPLAY_TREE_HPP_ 2 #define _SPLAY_TREE_HPP_ 3 4 #include <iomanip> 5 #include <iostream> 6 using namespace std; 7 8 template <class T> 9 class SplayTreeNode{ 10 public: 11 T key; // 关键字(键值) 12 SplayTreeNode *left; // 左孩子 13 SplayTreeNode *right; // 右孩子 14 15 16 SplayTreeNode():left(NULL),right(NULL) {} 17 18 SplayTreeNode(T value, SplayTreeNode *l, SplayTreeNode *r): 19 key(value), left(l),right(r) {} 20 }; 21 22 template <class T> 23 class SplayTree { 24 private: 25 SplayTreeNode<T> *mRoot; // 根结点 26 27 public: 28 SplayTree(); 29 ~SplayTree(); 30 31 // 前序遍历"伸展树" 32 void preOrder(); 33 // 中序遍历"伸展树" 34 void inOrder(); 35 // 后序遍历"伸展树" 36 void postOrder(); 37 38 // (递归实现)查找"伸展树"中键值为key的节点 39 SplayTreeNode<T>* search(T key); 40 // (非递归实现)查找"伸展树"中键值为key的节点 41 SplayTreeNode<T>* iterativeSearch(T key); 42 43 // 查找最小结点:返回最小结点的键值。 44 T minimum(); 45 // 查找最大结点:返回最大结点的键值。 46 T maximum(); 47 48 // 旋转key对应的节点为根节点,并返回值为根节点。 49 void splay(T key); 50 51 // 将结点(key为节点键值)插入到伸展树中 52 void insert(T key); 53 54 // 删除结点(key为节点键值) 55 void remove(T key); 56 57 // 销毁伸展树 58 void destroy(); 59 60 // 打印伸展树 61 void print(); 62 private: 63 64 // 前序遍历"伸展树" 65 void preOrder(SplayTreeNode<T>* tree) const; 66 // 中序遍历"伸展树" 67 void inOrder(SplayTreeNode<T>* tree) const; 68 // 后序遍历"伸展树" 69 void postOrder(SplayTreeNode<T>* tree) const; 70 71 // (递归实现)查找"伸展树x"中键值为key的节点 72 SplayTreeNode<T>* search(SplayTreeNode<T>* x, T key) const; 73 // (非递归实现)查找"伸展树x"中键值为key的节点 74 SplayTreeNode<T>* iterativeSearch(SplayTreeNode<T>* x, T key) const; 75 76 // 查找最小结点:返回tree为根结点的伸展树的最小结点。 77 SplayTreeNode<T>* minimum(SplayTreeNode<T>* tree); 78 // 查找最大结点:返回tree为根结点的伸展树的最大结点。 79 SplayTreeNode<T>* maximum(SplayTreeNode<T>* tree); 80 81 // 旋转key对应的节点为根节点,并返回值为根节点。 82 SplayTreeNode<T>* splay(SplayTreeNode<T>* tree, T key); 83 84 // 将结点(z)插入到伸展树(tree)中 85 SplayTreeNode<T>* insert(SplayTreeNode<T>* &tree, SplayTreeNode<T>* z); 86 87 // 删除伸展树(tree)中的结点(键值为key),并返回被删除的结点 88 SplayTreeNode<T>* remove(SplayTreeNode<T>* &tree, T key); 89 90 // 销毁伸展树 91 void destroy(SplayTreeNode<T>* &tree); 92 93 // 打印伸展树 94 void print(SplayTreeNode<T>* tree, T key, int direction); 95 }; 96 97 /* 98 * 构造函数 99 */ 100 template <class T> 101 SplayTree<T>::SplayTree():mRoot(NULL) 102 { 103 } 104 105 /* 106 * 析构函数 107 */ 108 template <class T> 109 SplayTree<T>::~SplayTree() 110 { 111 destroy(mRoot); 112 } 113 114 /* 115 * 前序遍历"伸展树" 116 */ 117 template <class T> 118 void SplayTree<T>::preOrder(SplayTreeNode<T>* tree) const 119 { 120 if(tree != NULL) 121 { 122 cout<< tree->key << " " ; 123 preOrder(tree->left); 124 preOrder(tree->right); 125 } 126 } 127 128 template <class T> 129 void SplayTree<T>::preOrder() 130 { 131 preOrder(mRoot); 132 } 133 134 /* 135 * 中序遍历"伸展树" 136 */ 137 template <class T> 138 void SplayTree<T>::inOrder(SplayTreeNode<T>* tree) const 139 { 140 if(tree != NULL) 141 { 142 inOrder(tree->left); 143 cout<< tree->key << " " ; 144 inOrder(tree->right); 145 } 146 } 147 148 template <class T> 149 void SplayTree<T>::inOrder() 150 { 151 inOrder(mRoot); 152 } 153 154 /* 155 * 后序遍历"伸展树" 156 */ 157 template <class T> 158 void SplayTree<T>::postOrder(SplayTreeNode<T>* tree) const 159 { 160 if(tree != NULL) 161 { 162 postOrder(tree->left); 163 postOrder(tree->right); 164 cout<< tree->key << " " ; 165 } 166 } 167 168 template <class T> 169 void SplayTree<T>::postOrder() 170 { 171 postOrder(mRoot); 172 } 173 174 /* 175 * (递归实现)查找"伸展树x"中键值为key的节点 176 */ 177 template <class T> 178 SplayTreeNode<T>* SplayTree<T>::search(SplayTreeNode<T>* x, T key) const 179 { 180 if (x==NULL || x->key==key) 181 return x; 182 183 if (key < x->key) 184 return search(x->left, key); 185 else 186 return search(x->right, key); 187 } 188 189 template <class T> 190 SplayTreeNode<T>* SplayTree<T>::search(T key) 191 { 192 return search(mRoot, key); 193 } 194 195 /* 196 * (非递归实现)查找"伸展树x"中键值为key的节点 197 */ 198 template <class T> 199 SplayTreeNode<T>* SplayTree<T>::iterativeSearch(SplayTreeNode<T>* x, T key) const 200 { 201 while ((x!=NULL) && (x->key!=key)) 202 { 203 if (key < x->key) 204 x = x->left; 205 else 206 x = x->right; 207 } 208 209 return x; 210 } 211 212 template <class T> 213 SplayTreeNode<T>* SplayTree<T>::iterativeSearch(T key) 214 { 215 return iterativeSearch(mRoot, key); 216 } 217 218 /* 219 * 查找最小结点:返回tree为根结点的伸展树的最小结点。 220 */ 221 template <class T> 222 SplayTreeNode<T>* SplayTree<T>::minimum(SplayTreeNode<T>* tree) 223 { 224 if (tree == NULL) 225 return NULL; 226 227 while(tree->left != NULL) 228 tree = tree->left; 229 return tree; 230 } 231 232 template <class T> 233 T SplayTree<T>::minimum() 234 { 235 SplayTreeNode<T> *p = minimum(mRoot); 236 if (p != NULL) 237 return p->key; 238 239 return (T)NULL; 240 } 241 242 /* 243 * 查找最大结点:返回tree为根结点的伸展树的最大结点。 244 */ 245 template <class T> 246 SplayTreeNode<T>* SplayTree<T>::maximum(SplayTreeNode<T>* tree) 247 { 248 if (tree == NULL) 249 return NULL; 250 251 while(tree->right != NULL) 252 tree = tree->right; 253 return tree; 254 } 255 256 template <class T> 257 T SplayTree<T>::maximum() 258 { 259 SplayTreeNode<T> *p = maximum(mRoot); 260 if (p != NULL) 261 return p->key; 262 263 return (T)NULL; 264 } 265 266 267 /* 268 * 旋转key对应的节点为根节点,并返回值为根节点。 269 * 270 * 注意: 271 * (a):伸展树中存在"键值为key的节点"。 272 * 将"键值为key的节点"旋转为根节点。 273 * (b):伸展树中不存在"键值为key的节点",并且key < tree->key。 274 * b-1 "键值为key的节点"的前驱节点存在的话,将"键值为key的节点"的前驱节点旋转为根节点。 275 * b-2 "键值为key的节点"的前驱节点存在的话,则意味着,key比树中任何键值都小,那么此时,将最小节点旋转为根节点。 276 * (c):伸展树中不存在"键值为key的节点",并且key > tree->key。 277 * c-1 "键值为key的节点"的后继节点存在的话,将"键值为key的节点"的后继节点旋转为根节点。 278 * c-2 "键值为key的节点"的后继节点不存在的话,则意味着,key比树中任何键值都大,那么此时,将最大节点旋转为根节点。 279 */ 280 template <class T> 281 SplayTreeNode<T>* SplayTree<T>::splay(SplayTreeNode<T>* tree, T key) 282 { 283 SplayTreeNode<T> N, *l, *r, *c; 284 285 if (tree == NULL) 286 return tree; 287 288 N.left = N.right = NULL; 289 l = r = &N; 290 291 for (;;) 292 { 293 if (key < tree->key) 294 { 295 if (tree->left == NULL) 296 break; 297 if (key < tree->left->key) 298 { 299 c = tree->left; /* rotate right */ 300 tree->left = c->right; 301 c->right = tree; 302 tree = c; 303 if (tree->left == NULL) 304 break; 305 } 306 r->left = tree; /* link right */ 307 r = tree; 308 tree = tree->left; 309 } 310 else if (key > tree->key) 311 { 312 if (tree->right == NULL) 313 break; 314 if (key > tree->right->key) 315 { 316 c = tree->right; /* rotate left */ 317 tree->right = c->left; 318 c->left = tree; 319 tree = c; 320 if (tree->right == NULL) 321 break; 322 } 323 l->right = tree; /* link left */ 324 l = tree; 325 tree = tree->right; 326 } 327 else 328 { 329 break; 330 } 331 } 332 333 l->right = tree->left; /* assemble */ 334 r->left = tree->right; 335 tree->left = N.right; 336 tree->right = N.left; 337 338 return tree; 339 } 340 341 template <class T> 342 void SplayTree<T>::splay(T key) 343 { 344 mRoot = splay(mRoot, key); 345 } 346 347 /* 348 * 将结点插入到伸展树中,并返回根节点 349 * 350 * 参数说明: 351 * tree 伸展树的根结点 352 * key 插入的结点的键值 353 * 返回值: 354 * 根节点 355 */ 356 template <class T> 357 SplayTreeNode<T>* SplayTree<T>::insert(SplayTreeNode<T>* &tree, SplayTreeNode<T>* z) 358 { 359 SplayTreeNode<T> *y = NULL; 360 SplayTreeNode<T> *x = tree; 361 362 // 查找z的插入位置 363 while (x != NULL) 364 { 365 y = x; 366 if (z->key < x->key) 367 x = x->left; 368 else if (z->key > x->key) 369 x = x->right; 370 else 371 { 372 cout << "不允许插入相同节点(" << z->key << ")!" << endl; 373 delete z; 374 return tree; 375 } 376 } 377 378 if (y==NULL) 379 tree = z; 380 else if (z->key < y->key) 381 y->left = z; 382 else 383 y->right = z; 384 385 return tree; 386 } 387 388 template <class T> 389 void SplayTree<T>::insert(T key) 390 { 391 SplayTreeNode<T> *z=NULL; 392 393 // 如果新建结点失败,则返回。 394 if ((z=new SplayTreeNode<T>(key,NULL,NULL)) == NULL) 395 return ; 396 397 // 插入节点 398 mRoot = insert(mRoot, z); 399 // 将节点(key)旋转为根节点 400 mRoot = splay(mRoot, key); 401 } 402 403 /* 404 * 删除结点(节点的键值为key),返回根节点 405 * 406 * 参数说明: 407 * tree 伸展树的根结点 408 * key 待删除结点的键值 409 * 返回值: 410 * 根节点 411 */ 412 template <class T> 413 SplayTreeNode<T>* SplayTree<T>::remove(SplayTreeNode<T>* &tree, T key) 414 { 415 SplayTreeNode<T> *x; 416 417 if (tree == NULL) 418 return NULL; 419 420 // 查找键值为key的节点,找不到的话直接返回。 421 if (search(tree, key) == NULL) 422 return tree; 423 424 // 将key对应的节点旋转为根节点。 425 tree = splay(tree, key); 426 427 if (tree->left != NULL) 428 { 429 // 将"tree的前驱节点"旋转为根节点 430 x = splay(tree->left, key); 431 // 移除tree节点 432 x->right = tree->right; 433 } 434 else 435 x = tree->right; 436 437 delete tree; 438 439 return x; 440 441 } 442 443 template <class T> 444 void SplayTree<T>::remove(T key) 445 { 446 mRoot = remove(mRoot, key); 447 } 448 449 /* 450 * 销毁伸展树 451 */ 452 template <class T> 453 void SplayTree<T>::destroy(SplayTreeNode<T>* &tree) 454 { 455 if (tree==NULL) 456 return ; 457 458 if (tree->left != NULL) 459 destroy(tree->left); 460 if (tree->right != NULL) 461 destroy(tree->right); 462 463 delete tree; 464 } 465 466 template <class T> 467 void SplayTree<T>::destroy() 468 { 469 destroy(mRoot); 470 } 471 472 /* 473 * 打印"伸展树" 474 * 475 * key -- 节点的键值 476 * direction -- 0,表示该节点是根节点; 477 * -1,表示该节点是它的父结点的左孩子; 478 * 1,表示该节点是它的父结点的右孩子。 479 */ 480 template <class T> 481 void SplayTree<T>::print(SplayTreeNode<T>* tree, T key, int direction) 482 { 483 if(tree != NULL) 484 { 485 if(direction==0) // tree是根节点 486 cout << setw(2) << tree->key << " is root" << endl; 487 else // tree是分支节点 488 cout << setw(2) << tree->key << " is " << setw(2) << key << "'s " << setw(12) << (direction==1?"right child" : "left child") << endl; 489 490 print(tree->left, tree->key, -1); 491 print(tree->right,tree->key, 1); 492 } 493 } 494 495 template <class T> 496 void SplayTree<T>::print() 497 { 498 if (mRoot != NULL) 499 print(mRoot, mRoot->key, 0); 500 } 501 #endif
伸展树的测试程序(SplayTreeTest.cpp)
1 /** 2 * C++ 语言: 伸展树 3 * 4 * @author skywang 5 * @date 2014/02/03 6 */ 7 8 #include <iostream> 9 #include "SplayTree.h" 10 using namespace std; 11 12 static int arr[]= {10,50,40,30,20,60}; 13 #define TBL_SIZE(a) ( (sizeof(a)) / (sizeof(a[0])) ) 14 15 int main() 16 { 17 int i,ilen; 18 SplayTree<int>* tree=new SplayTree<int>(); 19 20 cout << "== 依次添加: "; 21 ilen = TBL_SIZE(arr); 22 for(i=0; i<ilen; i++) 23 { 24 cout << arr[i] <<" "; 25 tree->insert(arr[i]); 26 } 27 28 cout << " == 前序遍历: "; 29 tree->preOrder(); 30 31 cout << " == 中序遍历: "; 32 tree->inOrder(); 33 34 cout << " == 后序遍历: "; 35 tree->postOrder(); 36 cout << endl; 37 38 cout << "== 最小值: " << tree->minimum() << endl; 39 cout << "== 最大值: " << tree->maximum() << endl; 40 cout << "== 树的详细信息: " << endl; 41 tree->print(); 42 43 i = 30; 44 cout << " == 旋转节点(" << i << ")为根节点"; 45 tree->splay(i); 46 cout << " == 树的详细信息: " << endl; 47 tree->print(); 48 49 // 销毁二叉树 50 tree->destroy(); 51 52 return 0; 53 }
关于"队列的声明和实现都在头文件中"的原因,是因为队列的实现利用了C++模板,而"C++编译器不能支持对模板的分离式编译"!
伸展树的C++测试程序
伸展树的测试程序运行结果如下:
== 依次添加: 10 50 40 30 20 60 == 前序遍历: 60 30 20 10 50 40 == 中序遍历: 10 20 30 40 50 60 == 后序遍历: 10 20 40 50 30 60 == 最小值: 10 == 最大值: 60 == 树的详细信息: 60 is root 30 is 60's left child 20 is 30's left child 10 is 20's left child 50 is 30's right child 40 is 50's left child == 旋转节点(30)为根节点 == 树的详细信息: 30 is root 20 is 30's left child 10 is 20's left child 60 is 30's right child 50 is 60's left child 40 is 50's left child
测试程序的主要流程是:新建伸展树,然后向伸展树中依次插入10,50,40,30,20,60。插入完毕这些数据之后,伸展树的节点是60;此时,再旋转节点,使得30成为根节点。
依次插入10,50,40,30,20,60示意图如下:
将30旋转为根节点的示意图如下: