概要
上一章介紹了伸展樹的基本概念,並通過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 << "\n== 前序遍歷: "; 29 tree->preOrder(); 30 31 cout << "\n== 中序遍歷: "; 32 tree->inOrder(); 33 34 cout << "\n== 后序遍歷: "; 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 << "\n== 旋轉節點(" << i << ")為根節點"; 45 tree->splay(i); 46 cout << "\n== 樹的詳細信息: " << 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旋轉為根節點的示意圖如下:
