1. 程式人生 > >c++ 搜尋二叉樹 插入,刪除,遍歷操作

c++ 搜尋二叉樹 插入,刪除,遍歷操作

搜尋二叉樹是一種具有良好排序和查詢效能的二叉樹資料結構,包括多種操作,本篇只介紹插入,排序(遍歷),和刪除操作,重點是刪除操作比較複雜,用到的例子也是本人親自畫的

用到的測試圖資料例子

第一、構建節點

 1 template <typename T> class BST;
 2 template <typename T> class BSTNode {
 3 public:
 4     friend class BST<T>;
 5     BSTNode() {
 6         lChild = rChild = parent = NULL;
7 data = NULL; 8 } 9 BSTNode(T d) { 10 lChild = rChild = parent = NULL; 11 data = d; 12 } 13 private: 14 BSTNode<T> *lChild, *rChild, *parent; 15 T data; 16 };
View Code

第二、二叉樹標頭檔案定義

 1 template<typename T> class BST {
2 public: 3 BST() { } 4 5 //插入操作 6 void insert(BSTNode<T>*node); 7 8 //二叉查詢樹的中序遍歷,就相當於排序了 9 void inSort(BSTNode<T>*node); 10 11 //按節點刪除 12 void deleteNode(BSTNode<T>* node); 13 14 //按數值刪除 15 void deleteNode(const T& t);
16 17 BSTNode<T>* search(T key); 18 BSTNode<T>* root=NULL; 19 20 private: 21 int count; 22 };
View Code

第三、搜尋二叉樹的插入

 1 template<typename T>
 2 void BST<T>::insert(BSTNode<T>* node)
 3 {
 4     BSTNode<T>* curr, *temp = NULL;
 5     curr = root;
 6     while (NULL!= curr) //遍歷二叉樹,找到應該插入的父節點
 7     {
 8         temp = curr;
 9         if (node->data>curr->data)
10         {
11             curr = curr->rChild;
12         }
13         else {
14             curr = curr->lChild;
15         }
16     }
17     node->parent = temp;//temp 程式碼當前最後遍歷的node,設定node->parent為該節點
18     if (temp==NULL)
19     {
20         root = node;
21         count++;
22     }
23     else {
24         if (node->data<temp->data)
25         {
26             temp->lChild = node;
27             count++;
28         }
29         else {
30             temp->rChild = node;
31             count++;
32         }
33     }
34 }
View Code

第四、搜尋二叉樹的刪除

 刪除包含多種情況,

1. 如果節點沒有子女,修改其父節點指標為NULL,刪除即可

2. 如果該節點有左孩子情況,修改其父親節點的指標和其左孩子的parent指標即可

3. 如果該節點有右孩子情況,修改其父親節點的指標和其右孩子的parent指標即可

4.如果同時有左右孩子的情況,情況比較複雜,一般有2種方法處理

    1) 用節點右邊孩子的最小值替換該節點,其他節點位置保持不變(本篇用這種方法)

    2)用節點左邊孩子的最大值替換該節點,其他節點位置保持不變

後面測試例子是刪除18 node,通過程式找到右邊最小值20,用20 替換18,其他節點位置保持不動。

 

  1 template<typename T>
  2 inline void BST<T>::deleteNode(BSTNode<T>* node)
  3 {
  4     BSTNode<T>*p = node->parent;//獲取node的父節點,這裡很重要
  5     if (node->lChild==NULL && node->rChild==NULL) //葉子節點直接刪除
  6     {
  7         if (node==node->parent->lChild)
  8         {
  9             node->parent->lChild = NULL;
 10         }
 11         else {
 12             node->parent->rChild = NULL;
 13         }
 14         delete node;
 15         count--;
 16     }
 17     else if (node->rChild != NULL && node->lChild == NULL) {//存在右孩子
 18         if (p==NULL)//說明節點為根節點
 19         {
 20             root = node->rChild;
 21             count--;
 22         }
 23         else {
 24             node->rChild->parent = p;
 25             if (p->lChild==node) //判斷是父節點的左孩子還是右孩子
 26             {
 27                 p->lChild = node->rChild;
 28             }
 29             else {
 30                 p->rChild = node->rChild;
 31             }
 32             delete node;
 33             count--;
 34         }        
 35     }
 36     else if (node->lChild!=NULL && node->rChild==NULL)//存在左孩子
 37     {
 38         if (p==NULL)
 39         {
 40             root = root->lChild;
 41             count--;
 42         }
 43         else {
 44             node->lChild->parent = p;
 45             if (p->lChild==node)
 46             {
 47                 p->lChild = node->lChild;
 48             }
 49             else {
 50                 p->rChild = node->lChild;
 51             }
 52             delete node;
 53             count--;
 54         }
 55     }
 56     else {
 57         BSTNode<T>*left, *curp=NULL;
 58         left = node->rChild; //本方案是找右側最小值,替換node節點,其他節點保持不動即可
 59         while (left!=NULL)
 60         {
 61             curp = left;
 62             left = left->lChild;
 63         }
 64 
 65         if (curp->rChild!=NULL)
 66         {
 67             if (curp->lChild==curp)
 68             {
 69                 curp->parent->lChild = curp->rChild;
 70             }
 71             else {
 72                 curp->parent->rChild = curp->rChild;
 73             }
 74         }
 75         else {
 76             if (curp->parent->lChild==curp)
 77             {
 78                 curp->parent->lChild = NULL;
 79             }
 80             else {
 81                 curp->parent->rChild = NULL;
 82             }
 83             //curp->parent->lChild = NULL;
 84         }
 85         //替curp 替換 node
 86         curp->parent = p;
 87         curp->lChild = node->lChild;
 88         curp->rChild = node->rChild;
 89 
 90         if (p->lChild==node)//判斷node 是p 的左孩子還是右孩
 91         {
 92             p->lChild = curp;
 93         }
 94         else {
 95             p->rChild = curp;
 96         }
 97         delete node;
 98         count--;
 99     }
100 }
View Code

第五、測試程式

 1 #include "pch.h"
 2 #include <iostream>
 3 #include "BSTree.h"
 4 using namespace std;
 5 
 6 int main()
 7 {  
 8     // 樹結構示意
 9     //     30
10     //    /  \
11     //  15   25
12     // /  \
13     //9    18
14     //   /   \
15     //  16   25
16     //      /  \
17     //    20    26  
18     BST<int> sbt;
19     sbt.insert(new BSTNode<int>(30));
20     sbt.insert(new BSTNode<int>(15));
21     sbt.insert(new BSTNode<int>(9));
22     sbt.insert(new BSTNode<int>(18));
23     sbt.insert(new BSTNode<int>(16));
24     sbt.insert(new BSTNode<int>(25));
25     sbt.insert(new BSTNode<int>(20));
26     sbt.insert(new BSTNode<int>(26));
27     sbt.insert(new BSTNode<int>(35));
28 
29     cout << "搜尋樹排序後:";
30     sbt.inSort(sbt.root);
31 
32     sbt.deleteNode(18);
33 
34     cout << endl << "刪除18 後排序:";
35 
36     sbt.inSort(sbt.root);
37 }
View Code

測試結果

 第六、所有程式程式碼

  1 #pragma once
  2 template <typename T> class BST;
  3 template <typename T> class BSTNode {
  4 public:
  5     friend class BST<T>;
  6     BSTNode() {
  7         lChild = rChild = parent = NULL;
  8         data = NULL;
  9     }
 10     BSTNode(T d) {
 11         lChild = rChild = parent = NULL;
 12         data = d;
 13     }
 14 private:
 15     BSTNode<T> *lChild, *rChild, *parent;
 16     T data;
 17 };
 18 
 19 template<typename T> class BST {
 20 public:    
 21     BST() { } 
 22 
 23     //插入操作
 24     void insert(BSTNode<T>*node);
 25 
 26     //二叉查詢樹的中序遍歷,就相當於排序了
 27     void inSort(BSTNode<T>*node);
 28 
 29     //按節點刪除
 30     void deleteNode(BSTNode<T>* node);
 31 
 32     //按數值刪除
 33     void deleteNode(const T& t);
 34 
 35     BSTNode<T>* search(T key);
 36     BSTNode<T>* root=NULL;
 37 
 38 private:    
 39     int count;
 40 };
 41 
 42 template<typename T>
 43 void BST<T>::insert(BSTNode<T>* node)
 44 {
 45     BSTNode<T>* curr, *temp = NULL;
 46     curr = root;
 47     while (NULL!= curr) //遍歷二叉樹,找到應該插入的父節點
 48     {
 49         temp = curr;
 50         if (node->data>curr->data)
 51         {
 52             curr = curr->rChild;
 53         }
 54         else {
 55             curr = curr->lChild;
 56         }
 57     }
 58     node->parent = temp;//temp 程式碼當前最後遍歷的node,設定node->parent為該節點
 59     if (temp==NULL)
 60     {
 61         root = node;
 62         count++;
 63     }
 64     else {
 65         if (node->data<temp->data)
 66         {
 67             temp->lChild = node;
 68             count++;
 69         }
 70         else {
 71             temp->rChild = node;
 72             count++;
 73         }
 74     }
 75 }
 76 
 77 template<typename T>
 78 void BST<T>::inSort(BSTNode<T>* node)
 79 {
 80     if (node!=NULL)
 81     {
 82         inSort(node->lChild);
 83         std::cout << node->data<<",";
 84         inSort(node->rChild);
 85     }
 86 }
 87 
 88 template<typename T>
 89 inline void BST<T>::deleteNode(BSTNode<T>* node)
 90 {
 91     BSTNode<T>*p = node->parent;//獲取node的父節點,這裡很重要
 92     if (node->lChild==NULL && node->rChild==NULL) //葉子節點直接刪除
 93     {
 94         if (node==node->parent->lChild)
 95         {
 96             node->parent->lChild = NULL;
 97         }
 98         else {
 99             node->parent->rChild = NULL;
100         }
101         delete node;
102         count--;
103     }
104     else if (node->rChild != NULL && node->lChild == NULL) {//存在右孩子
105         if (p==NULL)//說明節點為根節點
106         {
107             root = node->rChild;
108             count--;
109         }
110         else {
111             node->rChild->parent = p;
112             if (p->lChild==node) //判斷是父節點的左孩子還是右孩子
113             {
114                 p->lChild = node->rChild;
115             }
116             else {
117                 p->rChild = node->rChild;
118             }
119             delete node;
120             count--;
121         }        
122     }
123     else if (node->lChild!=NULL && node->rChild==NULL)//存在左孩子
124     {
125         if (p==NULL)
126         {
127             root = root->lChild;
128             count--;
129         }
130         else {
131             node->lChild->parent = p;
132             if (p->lChild==node)
133             {
134                 p->lChild = node->lChild;
135             }
136             else {
137                 p->rChild = node->lChild;
138             }
139             delete node;
140             count--;
141         }
142     }
143     else {
144         BSTNode<T>*left, *curp=NULL;
145         left = node->rChild; //本方案是找右側最小值,替換node節點,其他節點保持不動即可
146         while (left!=NULL)
147         {
148             curp = left;
149             left = left->lChild;
150         }
151 
152         if (curp->rChild!=NULL)
153         {
154             if (curp->lChild==curp)
155             {
156                 curp->parent->lChild = curp->rChild;
157             }
158             else {
159                 curp->parent->rChild = curp->rChild;
160             }
161         }
162         else {
163             if (curp->parent->lChild==curp)
164             {
165                 curp->parent->lChild = NULL;
166             }
167             else {
168                 curp->parent->rChild = NULL;
169             }
170             //curp->parent->lChild = NULL;
171         }
172         //替curp 替換 node
173         curp->parent = p;
174         curp->lChild = node->lChild;
175         curp->rChild = node->rChild;
176 
177         if (p->lChild==node)//判斷node 是p 的左孩子還是右孩
178         {
179             p->lChild = curp;
180         }
181         else {
182             p->rChild = curp;
183         }
184         delete node;
185         count--;
186     }
187 }
188 
189 template<typename T>
190 inline void BST<T>::deleteNode(const T & k)
191 {
192     BSTNode<T>*node = search(k);
193     if (node!=NULL)
194     {
195         deleteNode(node);
196     }
197 }
198 
199 
200 template<typename T>
201 inline BSTNode<T>* BST<T>::search(T k)
202 {
203     BSTNode<T>*node = root;
204     while (node!=NULL)
205     {
206         if (k<node->data)
207         {
208             node = node->lChild;
209         }
210         else if (k> node->data)
211         {
212             node = node->rChild;
213         }
214         else {
215             break;
216         }
217     }
218     return node;
219 }
BSTree.h