1. 程式人生 > >資料結構---二叉搜尋樹BST實現(C++)

資料結構---二叉搜尋樹BST實現(C++)

1. 二叉查詢樹

二叉查詢樹(Binary Search Tree),也稱為二叉搜尋樹、有序二叉樹(ordered binary tree)或排序二叉樹(sorted binary tree),是指一棵空樹或者具有下列性質的二叉樹:

  1. 若任意節點的左子樹不空,則左子樹上所有節點的值均小於它的根節點的值;
  2. 若任意節點的右子樹不空,則右子樹上所有節點的值均大於它的根節點的值;
  3. 任意節點的左、右子樹也分別為二叉查詢樹;
  4. 沒有鍵值相等的節點。

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]