c++ 搜尋二叉樹 插入,刪除,遍歷操作
阿新 • • 發佈:2018-12-29
搜尋二叉樹是一種具有良好排序和查詢效能的二叉樹資料結構,包括多種操作,本篇只介紹插入,排序(遍歷),和刪除操作,重點是刪除操作比較複雜,用到的例子也是本人親自畫的
用到的測試圖資料例子
第一、構建節點
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;View Code7 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 };
第二、二叉樹標頭檔案定義
1 template<typename T> class BST {View Code2 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 };
第三、搜尋二叉樹的插入
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