資料結構---二叉搜尋樹BST實現(C++)
1. 二叉查詢樹
二叉查詢樹(Binary Search Tree),也稱為二叉搜尋樹、有序二叉樹(ordered binary tree)或排序二叉樹(sorted binary tree),是指一棵空樹或者具有下列性質的二叉樹:
- 若任意節點的左子樹不空,則左子樹上所有節點的值均小於它的根節點的值;
- 若任意節點的右子樹不空,則右子樹上所有節點的值均大於它的根節點的值;
- 任意節點的左、右子樹也分別為二叉查詢樹;
- 沒有鍵值相等的節點。
2. 節點類
1 class BSTNode{ 2 public: 3 int data; 4 BSTNode *left;5 BSTNode *right; 6 BSTNode(int x): 7 data(x), left(NULL), right(NULL){} 8 };
在寫程式碼的過程中發現有的類方法需要經常使用某節點的父節點,所以可以考慮在資料成員中新增父節點 BSTNode* parents ,本文是在BSTree的方法中添加了函式 BSTNode* BSTree::getParents(int value)
3. 二叉搜尋樹類
1 class BSTree{ 2 public: 3 BSTNode *root;4 BSTree(): 5 root(NULL){} 6 ~BSTree(){destory(root);} 7 8 // 是否為空 9 bool isEmpty(); 10 // 深度 11 int depth(BSTNode *&proot); 12 // 節點數 13 int size(BSTNode *&proot); 14 // 葉子節點數 15 int leafsize(BSTNode *&proot); 16 17 // 前序遍歷 18 void preOrder(BSTNode* &pRoot);19 // 中序遍歷 20 void inOrder(BSTNode* &pRoot); 21 // 後序遍歷 22 void postOrder(BSTNode* &pRoot); 23 // 層序遍歷 24 void levelOrder(BSTNode* &pRoot); 25 26 // 查詢 27 bool search(int value); 28 // 插入 29 void insert(int value); 30 // 刪除 31 void remove(int value); 32 33 // 尋找前驅節點 34 BSTNode* predecessor(int value); 35 // 尋找後繼節點 36 BSTNode* successor(int value); 37 38 // 最小值 39 int minimum(); 40 // 最大值 41 int maximum(); 42 43 // 銷燬BST 44 void destory(BSTNode *&proot); 45 46 private: 47 // 獲取value節點的地址 48 BSTNode* getAddr(int value); 49 // 獲取value父節點的地址 50 BSTNode* getParents(int value); 51 };
4. 主要方法
對於基本的方法,如深度、節點數、葉子節點數沒什麼難點;
對於三種遍歷方法使用的是經典的遞迴方法;
對於BST的最大/最小值,主要記住最小值永遠在根節點的最左邊,最大值永遠在根節點的最右邊,只需要不停的向最左或最優遍歷即可,直到空節點結束(最大最小值也可能是根節點);
BST的難點可能就在節點刪除的部分,以下圖所示的樹為物件,講一下節點刪除:
/* * 62 * / \ * 58 88 * / / \ * 47 73 99 * / \ / * 35 51 93 * / \ / \ * 29 37 49 56 * / / \ * 36 48 50 * */
被刪除的節點可能是一下3種情況之一:
1. 葉子節點 2. 只含有左子樹或只含有右子樹的節點 3. 同時含有左右子樹的節點
細分:
1. 葉子節點
1.1 樹只含有一個節點,刪除葉子節點
如果樹只有一個節點,則該節點即是根節點又是葉節點,刪除時需要將root置空
1.2 樹含有至少2個節點,刪除葉子節點
如圖上的 29 36 73等,刪除葉子節點對BST沒有影響,刪除即可,同時需要維護指標;
2. 僅有左或者右子樹的節點
2.1 僅有左子樹的節點,同時該節點是根節點
2.2 僅有左子樹的節點,同時該節點非根節點
2.3 僅有右子樹的節點,同時該節點是根節點
2.4 僅有右子樹的節點,同時該節點非根節點
上述四種情況只需要將待刪節點的左右孩子放到待刪節點的位置即可,同時注意是不是需要維護根節點
3. 左右子樹都有的節點
首先尋找待刪節點的直接前驅,然後用直接前驅代替待刪節點。如刪除47,47的前驅是37,那麼將37節點的資料複製到47節點,釋放37,同時將35的右孩子指向36,原47節點的右子樹不動。
以上具體細節見完整程式碼
5. 完整程式碼
1 #include<iostream> 2 #include<vector> 3 #include<queue> 4 using namespace std; 5 6 class BSTNode{ 7 public: 8 int data; 9 BSTNode *left; 10 BSTNode *right; 11 BSTNode(int x): 12 data(x), left(NULL), right(NULL){} 13 }; 14 15 class BSTree{ 16 public: 17 BSTNode *root; 18 BSTree(): 19 root(NULL){} 20 ~BSTree(){destory(root);} 21 22 // 是否為空 23 bool isEmpty(); 24 // 深度 25 int depth(BSTNode *&proot); 26 // 節點數 27 int size(BSTNode *&proot); 28 // 葉子節點數 29 int leafsize(BSTNode *&proot); 30 31 // 前序遍歷 32 void preOrder(BSTNode* &pRoot); 33 // 中序遍歷 34 void inOrder(BSTNode* &pRoot); 35 // 後序遍歷 36 void postOrder(BSTNode* &pRoot); 37 // 層序遍歷 38 void levelOrder(BSTNode* &pRoot); 39 40 // 查詢 41 bool search(int value); 42 // 插入 43 void insert(int value); 44 // 刪除 45 void remove(int value); 46 47 // 尋找前驅節點 48 BSTNode* predecessor(int value); 49 // 尋找後繼節點 50 BSTNode* successor(int value); 51 52 // 最小值 53 int minimum(); 54 // 最大值 55 int maximum(); 56 57 // 銷燬BST 58 void destory(BSTNode *&proot); 59 60 private: 61 // 獲取value節點的地址 62 BSTNode* getAddr(int value); 63 // 獲取value父節點的地址 64 BSTNode* getParents(int value); 65 }; 66 67 bool BSTree::isEmpty(){ 68 return root==NULL; 69 } 70 71 int BSTree::depth(BSTNode *&proot){ 72 if(proot == NULL) 73 return 0; 74 int left = depth(proot->left); 75 int right = depth(proot->right); 76 if(left > right) 77 return left + 1; 78 else 79 return right + 1; 80 } 81 82 int BSTree::size(BSTNode *&proot){ 83 if(proot == NULL) 84 return 0; 85 int left = size(proot->left); 86 int right = size(proot->right); 87 return left + right + 1; 88 } 89 90 int BSTree::leafsize(BSTNode *&proot){ 91 if(proot == NULL) 92 return 0; 93 if(proot->left == NULL && proot->right == NULL) 94 return 1; 95 int leftLeaf = leafsize(proot->left); 96 int rightLeaf = leafsize(proot->right); 97 return leftLeaf + rightLeaf; 98 } 99 100 BSTNode* BSTree::getParents(int value){ 101 if(BSTree::search(value) == true){ 102 BSTNode* pRoot = root; 103 BSTNode* parents; // 用於儲存value節點的父節點 104 while(pRoot->data!=value){ 105 parents = pRoot; 106 if(pRoot->data > value) 107 pRoot = pRoot->left; 108 else 109 pRoot = pRoot->right; 110 } 111 if(pRoot == root){ 112 //cout<<"the value is root of the tree, NO PARENTS."<<endl; 113 return NULL; 114 } 115 else 116 return parents; 117 } 118 else{ 119 cout<<"the value is not in the tree."<<endl; 120 return NULL; 121 } 122 } 123 124 BSTNode* BSTree::getAddr(int value){ 125 if(BSTree::search(value) == true){ 126 BSTNode* pRoot = root; 127 while(pRoot->data!=value){ 128 if(pRoot->data > value) 129 pRoot = pRoot->left; 130 else 131 pRoot = pRoot->right; 132 } 133 return pRoot; 134 } 135 else{ 136 cout<<"the value is not in the tree."<<endl; 137 return NULL; 138 } 139 } 140 141 // 若value不在樹內或者value沒有前驅,返回null,否則,返回前驅節點地址 142 BSTNode* BSTree::predecessor(int value){ 143 if(!search(value)){ 144 cout<<"the value is not in the tree."<<endl; 145 return NULL; 146 } 147 else if(BSTree::minimum() == value){ 148 cout<<"節點"<<value<<"沒有前驅節點"<<endl; 149 return NULL; 150 } 151 else{ 152 BSTNode* pRoot = getAddr(value);// 用於儲存value節點的地址 153 BSTNode* parents = getParents(value); // 用於儲存value的父節點地址 154 // 含左子樹的節點 155 if(pRoot->left != NULL){ 156 BSTNode* pre = pRoot->left; 157 while(pre->right != NULL){ 158 pre = pre->right; 159 } 160 return pre; 161 } 162 //沒有左子樹的節點 163 else{ 164 if(parents->right == pRoot) 165 return parents; 166 else if(parents->left == pRoot){ 167 while(parents->data > value) 168 parents = getParents(parents->data); 169 return parents; 170 } 171 } 172 } 173 } 174 175 // 若value不在樹內或者value沒有後繼,返回null,否則,返回前後繼節點地址 176 BSTNode* BSTree::successor(int value){ 177 if(!search(value)){ 178 cout<<"the value is not in the tree."<<endl; 179 return NULL; 180 } 181 else if(BSTree::maximum() == value){ 182 cout<<"節點"<<value<<"沒有後繼節點"<<endl; 183 return NULL; 184 } 185 else{ 186 BSTNode* pRoot = getAddr(value);// 用於儲存value節點的地址 187 BSTNode* parents = getParents(value); // 用於儲存value的父節點地址 188 // 含右子樹的節點 189 if(pRoot->right != NULL){ 190 BSTNode* pre = pRoot->right; 191 while(pre->left != NULL){ 192 pre = pre->left; 193 } 194 return pre; 195 } 196 //沒有右子樹的節點 197 else{ 198 if(parents->left == pRoot) 199 return parents; 200 else if(parents->right == pRoot){ 201 while(parents->data < value) 202 parents = getParents(parents->data); 203 return parents; 204 } 205 } 206 } 207 } 208 209 int BSTree::minimum(){ 210 BSTNode* proot = root; 211 while(proot->left != NULL){ 212 proot = proot->left; 213 } 214 return proot->data; 215 } 216 217 int BSTree::maximum(){ 218 BSTNode* proot = root; 219 while(proot->right != NULL){ 220 proot = proot->right; 221 } 222 return proot->data; 223 } 224 225 /* 226 * 62 227 * / \ 228 * 58 88 229 * / / \ 230 * 47 73 99 231 * / \ / 232 * 35 51 93 233 * / \ / \ 234 * 29 37 49 56 235 * / / \ 236 * 36 48 50 237 * 238 * 刪除節點的3種情況: 239 * 1. 葉子節點 240 * 1.1 樹只含有一個節點,刪除葉子節點 241 * 1.2 樹含有至少2個節點,刪除葉子節點 242 * 2. 僅有左或者右子樹的節點 243 * 2.1 僅有左子樹的節點,刪除根節點 244 * 2.2 僅有左子樹的節點,刪除非根節點 245 * 2.3 僅有右子樹的節點,刪除根節點 246 * 2.4 僅有右子樹的節點,刪除非根節點 247 * 3. 左右子樹都有的節點 248 * 249 */ 250 251 void BSTree::remove(int value){ 252 if(!search(value)){ 253 cout<<"the value is not in the tree. please check."<<endl; 254 return ; 255 } 256 else{ 257 // 查詢value節點 258 BSTNode* pRoot = getAddr(value);// 用於儲存value節點的地址 259 BSTNode* parents = getParents(value); // 用於儲存待刪除節點的父節點 260 // 刪除value節點 261 // 1.葉節點 262 // 1.1 樹只含有一個節點 263 if(pRoot == root && pRoot->left == NULL && pRoot->right == NULL){ 264 root = NULL; 265 free(pRoot); 266 } 267 // 1.2 樹含有至少2個節點 268 else if(pRoot != root && pRoot->left == NULL && pRoot->right == NULL){ 269 // 待刪節點是父節點的右孩子 270 if(parents->right != NULL && parents->right->data == value){ 271 parents->right = NULL; 272 free(pRoot); 273 } 274 // 待刪節點是父節點的左孩子 275 else{ 276 parents->left = NULL; 277 free(pRoot); 278 } 279 } 280 // 2. 僅有左子樹或右子樹的節點 281 // 2.1 僅有左子樹,且刪除根節點 282 else if(pRoot == root && pRoot->left != NULL && pRoot->right == NULL){ 283 root = pRoot->left; 284 free(pRoot); 285 } 286 // 2.2 僅有左子樹的節點,刪除非根節點 287 else if(pRoot != root && pRoot->left != NULL && pRoot->right == NULL){ 288 // 待刪節點是父節點的右孩子 289 if(parents->right != NULL && parents->right->data == value){ 290 parents->right = pRoot->left; 291 free(pRoot); 292 } 293 // 待刪節點是父節點的左孩子 294 else{ 295 parents->left = pRoot->left; 296 free(pRoot); 297 } 298 } 299 // 2.3 僅有右子樹的節點,刪除根節點 300 else if(pRoot == root && pRoot->left == NULL && pRoot->right != NULL){ 301 root = pRoot->right; 302 free(pRoot); 303 } 304 // 2.4 僅有右子樹的節點, 刪除非根節點 305 else if(pRoot != root && pRoot->left == NULL && pRoot->right != NULL){ 306 // 待刪節點是父節點的右孩子 307 if(parents->right != NULL && parents->right->data == value){ 308 parents->right = pRoot->right; 309 free(pRoot); 310 } 311 // 待刪節點是父節點的左孩子 312 else{ 313 parents->left = pRoot->right; 314 free(pRoot); 315 } 316 } 317 // 3. 左右子樹都有的節點 318 else{ 319 // 尋找待刪除節點的直接前驅 320 BSTNode* pre = predecessor(value);// pre儲存直接前驅 321 pRoot->data = pre->data;// 資料覆蓋 322 // 尋找直接前驅的左/右節點 323 if(pre->right != NULL){ 324 BSTNode *pRootNext = pRoot->right; 325 BSTNode *temp = pre->right; 326 if(pre == pRootNext) 327 pRoot->right = temp; 328 else 329 pRootNext->left = temp; 330 free(pre); 331 } 332 else if(pre->left != NULL){ 333 BSTNode *pRootNext = pRoot->left; 334 BSTNode *temp = pre->left; 335 if(pre == pRootNext) 336 pRoot->left = temp; 337 else 338 pRootNext->right = temp; 339 free(pre); 340 } 341 else if(pre->left == NULL && pre->right == NULL){ 342 pRoot->left = NULL; 343 free(pre); 344 } 345 } 346 } 347 } 348 349 350 bool BSTree::search(int value){ 351 BSTNode* pRoot = root; 352 while(pRoot!=NULL && pRoot->data!=value){ 353 if(pRoot->data > value) 354 pRoot = pRoot->left; 355 else 356 pRoot = pRoot->right; 357 } 358 if(pRoot == NULL) 359 return false; 360 else 361 return true; 362 } 363 364 void BSTree::insert(int value){ 365 // value節點已經存在 366 if(BSTree::search(value) == true){ 367 cout<<"the value "<<value<<" in the tree already."<<endl; 368 return ; 369 } 370 // value節點不存在 371 else{ 372 BSTNode* pRoot = root; 373 // 空樹 374 if(pRoot == NULL) 375 root = new BSTNode(value); 376 // 非空 377 else{ 378 BSTNode* temp; 379 while(pRoot!= NULL && pRoot->data!=value){ 380 temp = pRoot; 381 if(pRoot->data > value) 382 pRoot = pRoot->left; 383 else 384 pRoot = pRoot->right; 385 } 386 pRoot = temp; 387 if(pRoot->data>value) 388 pRoot->left = new BSTNode(value); 389 else 390 pRoot->right = new BSTNode(value); 391 } 392 } 393 cout<<"the value "<<value<<" is inserted."<<endl; 394 } 395 396 void BSTree::preOrder(BSTNode* &pRoot){ 397 if(pRoot == NULL) 398 return ; 399 cout<<pRoot->data<<' '; 400 preOrder(pRoot->left); 401 preOrder(pRoot->right); 402 } 403 404 void BSTree::inOrder(BSTNode* &pRoot){ 405 if(pRoot == NULL) 406 return ; 407 inOrder(pRoot->left); 408 cout<<pRoot->data<<' '; 409 inOrder(pRoot->right); 410 } 411 412 void BSTree::postOrder(BSTNode* &pRoot){ 413 if(pRoot == NULL) 414 return ; 415 postOrder(pRoot->left); 416 postOrder(pRoot->right); 417 cout<<pRoot->data<<' '; 418 } 419 420 void BSTree::levelOrder(BSTNode *&pRoot){ 421 queue<BSTNode*> p; 422 if(pRoot == NULL) 423 return ; 424 p.push(pRoot); 425 while (!p.empty()){ 426 BSTNode *temp = p.front(); 427 cout<<temp->data<<' '; 428 p.pop(); 429 if(temp->left) 430 p.push(temp->left); 431 if(temp->right) 432 p.push(temp->right); 433 } 434 } 435 436 void BSTree::destory(BSTNode *&proot){ 437 if (proot== NULL) 438 return ; 439 destory(proot->left); 440 destory(proot->right); 441 cout<<"free value "<<proot->data<<endl; 442 free(proot); 443 proot = NULL; 444 } 445 446 447 int main(int argc, char const *argv[]) 448 { 449 BSTree tree; 450 int arr[] = {62, 58, 47, 35, 29, 451 37, 36, 51, 49, 48, 452 50, 56, 88, 73, 99, 93}; 453 for(int i=0; i<16; i++) 454 tree.insert(arr[i]); 455 456 cout<<"前序遍歷: "; 457 tree.preOrder(tree.root); 458 cout<<endl; 459 cout<<"中序遍歷: "; 460 tree.inOrder(tree.root); 461 cout<<endl; 462 cout<<"最小值: "<<tree.minimum()<<endl; 463 cout<<"最大值: "<<tree.maximum()<<endl; 464 465 cout<<"深度: "<<tree.depth(tree.root)<<endl; 466 cout<<"節點數: "<<tree.size(tree.root)<<endl; 467 cout<<"葉子節點數: "<<tree.leafsize(tree.root)<<endl; 468 469 int index = 2; 470 BSTNode *pre = tree.predecessor(arr[index]); 471 if(pre != NULL) 472 cout<<"節點"<<arr[index]<<"的前驅節點是"<<pre->data<<endl; 473 474 BSTNode *suc = tree.successor(arr[index]); 475 if(suc != NULL) 476 cout<<"節點"<<arr[index]<<"的後繼節點是"<<suc->data<<endl; 477 478 cout<<"刪除節點: "<<arr[index]<<endl; 479 tree.remove(arr[index]); 480 481 cout<<"前序遍歷: "; 482 tree.preOrder(tree.root); 483 cout<<endl; 484 cout<<"中序遍歷: "; 485 tree.inOrder(tree.root); 486 cout<<endl; 487 488 tree.destory(tree.root); 489 return 0; 490 }View Code
6. 執行結果
6.1 測試使用的二叉搜尋樹
/* * 62 * / \ * 58 88 * / / \ * 47 73 99 * / \ / * 35 51 93 * / \ / \ * 29 37 49 56 * / / \ * 36 48 50 * */
6.2 執行結果
1 the value 62 is inserted. 2 the value 58 is inserted. 3 the value 47 is inserted. 4 the value 35 is inserted. 5 the value 29 is inserted. 6 the value 37 is inserted. 7 the value 36 is inserted. 8 the value 51 is inserted. 9 the value 49 is inserted. 10 the value 48 is inserted. 11 the value 50 is inserted. 12 the value 56 is inserted. 13 the value 88 is inserted. 14 the value 73 is inserted. 15 the value 99 is inserted. 16 the value 93 is inserted. 17 前序遍歷: 62 58 47 35 29 37 36 51 49 48 50 56 88 73 99 93 18 中序遍歷: 29 35 36 37 47 48 49 50 51 56 58 62 73 88 93 99 19 最小值: 29 20 最大值: 99 21 深度: 6 22 節點數: 16 23 葉子節點數: 7 24 節點47的前驅節點是37 25 節點47的後繼節點是48 26 刪除節點: 47 27 前序遍歷: 62 58 37 35 29 36 51 49 48 50 56 88 73 99 93 28 中序遍歷: 29 35 36 37 48 49 50 51 56 58 62 73 88 93 99 29 free value 29 30 free value 36 31 free value 35 32 free value 48 33 free value 50 34 free value 49 35 free value 56 36 free value 51 37 free value 37 38 free value 58 39 free value 73 40 free value 93 41 free value 99 42 free value 88 43 free value 62 44 [Finished in 2.1s]