经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
数据结构学习-BST二叉查找树 : 插入、删除、中序遍历、前序遍历、后序遍历、广度遍历、绘图
来源:cnblogs  作者:cyrio  时间:2018/12/17 9:47:53  对本文有异议

二叉查找树(Binary Search Tree)

是一种树形的存储数据的结构

如图所示,它具有的特点是:

1、具有一个根节点

2、每个节点可能有0、1、2个分支

3、对于某个节点,他的左分支小于自身,自身小于右分支

接下来我们用c++来实现BST的封装

首先我们编写每个节点的类结构,分析可以知道我们每一个节点需要存储一个数据(data),左分支(left指向一个节点),右分支(right指向另一个节点)

因此我们建立

bstNode.h

  1. #ifndef TEST1_BSTNODE_H
  2. #define TEST1_BSTNODE_H
  3. template <typename T> //这里使用模板类,以放入多种类型的数据,值得一提的是模板类不能讲声明和实现放在两个文件中
  4. class bstNode{
  5. public:
  6. T data;
  7. bstNode* left;
  8. bstNode* right;
  9. bstNode(){ //默认构造函数
  10. data = 0;
  11. left = nullptr;
  12. right = nullptr;
  13. }
  14. bstNode(T val){ //赋值构造函数
  15. data = val;
  16. left = nullptr;
  17. right = nullptr;
  18. }
  19. };
  20. #endif //TEST1_BSTNODE_H

 

接下来我们创建封装了各种方法的树形结构类:

myBST.h

 

这个头文件的设计思路如下:

 

1、先包含bstNode* root作为根节点,在通过根节点的左右指针延伸出整棵树;

 

2、封装了一些会用到的方法:搜索指定值(Search)、找出一颗子树中的最小值(treeMin)、插入指定值(Insert)、删除指定值(Delete)、判断是否是叶子结点(isLeaf)、判断是否有两个孩子(isNodeWithTwoChild)、

 

三种遍历方式(前序PreorderTraversal、中序InorderTraversal、后序Postodertraversal)、删除所有节点(DeleteAllNodes)、广度搜索进行周游(BFTraversal)、横着画图(Graph)、返回根节点(getRoot)、判断树空(isEmpty)

 

默认构造函数、vector为参数的构造函数、数组和长度为参数的构造函数、析构函数。

 

注意在这里为了防止公有方法直接调用私有数据,采用了创建以"__"开头的私有方法,让公有方法先来调用该私有方法,再让私有方法来调用私有数据,以确保其安全性。

 

  1. #ifndef TEST1_MYBST_H
  2. #define TEST1_MYBST_H
  3. #include <iomanip>
  4. #include "bstNode.h"
  5. #include <vector>
  6. #include <deque>
  7. #include <iostream>
  8. using namespace std;
  9. template <typename T>
  10. class myBST{
  11. private:
  12. bstNode<T> * root = nullptr;
  13. bstNode<T> * __search(bstNode<T> * root , const T &key){
  14. if (nullptr == root)
  15. return nullptr;
  16. if (key == root->data)
  17. return root;
  18. else if (key < root->data)
  19. return __search(root->left, key);
  20. else
  21. return __search(root->right, key);
  22. } //查找关键字是否存在
  23. bstNode<T> * __treeMin(bstNode<T> * root , bstNode<T> * &parent){
  24. bstNode<T> * curr = root;
  25. while(curr->left!= nullptr){
  26. parent = curr;
  27. curr = curr->left;
  28. }
  29. return curr;
  30. } //返回最小节点(一路向左)
  31. bool __Insert(const T &key){
  32. bstNode<T> * temp = new bstNode<T>(key);
  33. bstNode<T> * parent = nullptr;
  34. if(isEmpty()){
  35. root=temp;
  36. return true;
  37. }
  38. else{
  39. bstNode<T> * curr;
  40. curr = root;
  41. while(curr){
  42. parent = curr;
  43. if(temp->data>curr->data) curr=curr->right;
  44. else curr = curr->left;
  45. }
  46. if(temp->data<parent->data){
  47. parent->left=temp;
  48. return true;
  49. }
  50. else {
  51. parent->right = temp;
  52. return true;
  53. }
  54. }
  55. return false;
  56. } //插入指定值
  57. bool __Delete(const T &key){
  58. bool found = false;//存储有没有找到key的变量
  59. if(isEmpty()){
  60. cerr<<"BST为空"<<endl;
  61. return false;
  62. }
  63. bstNode<T> * curr = root;
  64. bstNode<T> * parrent = nullptr;
  65. while(curr!= nullptr) {
  66. if (key == curr->data) {
  67. found = true;
  68. break;
  69. } else {
  70. parrent = curr;
  71. if (key < curr->data) curr = curr->left;
  72. else curr = curr->right;
  73. }
  74. }
  75. if(!found){
  76. cerr<<"未找到key!"<<endl;
  77. return false;
  78. }
  79. if (parrent == nullptr){//删除根节点
  80. root = nullptr;
  81. delete(curr);
  82. return true;
  83. }
  84. /*
  85. 删除的节点有三种可能:
  86. 1、叶子结点
  87. 2、一个孩子的节点
  88. 3、两个孩子的节点
  89. */
  90. if (__isLeaf(curr)){ //删除的点是叶子结点
  91. if(parrent->left==curr) parrent->left= nullptr;
  92. else parrent->right= nullptr;
  93. delete(curr);
  94. return true;
  95. }
  96. else if(__isNodeWithTwoChild(curr)){ //是两个孩子的节点
  97. //以当前右子树中的最小值取代他
  98. bstNode<T> * parrent = curr;
  99. bstNode<T> * tmp = __treeMin(curr->right,parrent);
  100. curr->data = tmp->data;
  101. if(parrent->right==tmp)
  102. parrent->right== nullptr;
  103. else parrent->left== nullptr;
  104. delete(tmp);
  105. return true;
  106. }
  107. else{ //只有一个孩子的节点
  108. if(curr->left!= nullptr){
  109. if(curr->left == curr){
  110. parrent->left=curr->left;
  111. delete(curr);
  112. return true;
  113. }
  114. else{
  115. parrent->right=curr->right;
  116. delete(curr);
  117. return true;
  118. }
  119. }
  120. if(curr->right!= nullptr){
  121. if(curr->left == curr){
  122. parrent->left=curr->left;
  123. delete(curr);
  124. return true;
  125. }
  126. else{
  127. parrent->right=curr->right;
  128. delete(curr);
  129. return true;
  130. }
  131. }
  132. }
  133. return false;
  134. } //删除指定值
  135. bool __isLeaf(bstNode<T> * const & root){
  136. if(root->left== nullptr && root->right== nullptr) return true;
  137. else return false;
  138. }//判断是否是叶子节点
  139. bool __isNodeWithTwoChild(bstNode<T> * const & root){
  140. if(root->left!= nullptr && root->right!= nullptr) return true;
  141. else return false;
  142. }//判断是否有两个孩子
  143. void __InorderTraversal(bstNode<T> *root,std::vector<int>&result){
  144. if(nullptr == root) return;
  145. __InorderTraversal(root->left,result);
  146. cout<<root->data<<" ";
  147. result.push_back(root->data);
  148. __InorderTraversal(root->right,result);
  149. }//中序遍历
  150. void __PreorderTraversal(bstNode<T> *root,std::vector<int>&result){
  151. if(nullptr == root) return;
  152. cout<<root->data<<" ";
  153. result.push_back(root->data);
  154. __InorderTraversal(root->left,result);
  155. __InorderTraversal(root->right,result);
  156. }//前序遍历
  157. void __PostorderTraversal(bstNode<T> *root,std::vector<int>&result){
  158. if(nullptr == root) return;
  159. __InorderTraversal(root->left,result);
  160. __InorderTraversal(root->right,result);
  161. cout<<root->data<<" ";
  162. result.push_back(root->data);
  163. }//后序遍历
  164. void __DeleteAllNodes(bstNode<T> *root){
  165. if (root == nullptr) return;
  166. __DeleteAllNodes(root->left);
  167. __DeleteAllNodes(root->right);
  168. __Delete(root->data);
  169. }//删除所有节点
  170. void __BFTraversal(vector<T>&result) {
  171. deque<bstNode<T> *> TQueue;
  172. bstNode<T> *pointer = root;
  173. if (pointer != nullptr) {
  174. TQueue.push_back(pointer);
  175. }
  176. while (!TQueue.empty()) {
  177. pointer = TQueue.front();
  178. TQueue.pop_front();
  179. cout << pointer->data << " ";
  180. result.push_back(pointer->data);
  181. if (pointer->left != nullptr) TQueue.push_back(pointer->left);
  182. if (pointer->right != nullptr) TQueue.push_back(pointer->right);
  183. }
  184. } //广度搜索来进行周游
  185. void __Graph(int indent,bstNode<T>* root){
  186. if(root != 0){
  187. __Graph(indent + 8, root->right);
  188. cout<<setw(indent)<<" "<<root->data<<endl;
  189. __Graph(indent + 8, root->left);
  190. }
  191. } //横着画图的内部接口
  192. bstNode<T> * __GetRoot(){
  193. return root;
  194. } //返回根节点的内部接口
  195. public:
  196. myBST(){
  197. root = nullptr;
  198. } //默认构造
  199. myBST(vector<T> arr){
  200. root = nullptr;
  201. for(int i =0;i<(int)arr.size();i++){
  202. __Insert(arr[i]);
  203. }
  204. }
  205. myBST(T * arr,int len){
  206. root = nullptr;
  207. for(int i =0;i<len;i++){
  208. __Insert(*(arr+i));
  209. }
  210. }
  211. ~myBST(){
  212. bstNode<T> * curr = root;
  213. __DeleteAllNodes(curr);
  214. }//析构
  215. bool isEmpty() const{
  216. return root == nullptr;
  217. }//判断树空
  218. bool search(const T &key){
  219. bstNode<T> * temp = __search(root, key);
  220. return (temp == nullptr) ? false : true;
  221. }//查找关键字是否存在的对外接口
  222. bool Insert(const T &key){
  223. return __Insert(key);
  224. }//插入节点的外部接口
  225. bool Delete(const T &key){
  226. return __Delete(key);
  227. }//删除节点的外部接口
  228. void InorderTraversal(vector<T>&result){
  229. __InorderTraversal(root, result);
  230. }//中序遍历的外部接口
  231. void PreorderTraversal(vector<T>&result){
  232. __PreorderTraversal(root, result);
  233. }//前序遍历的外部接口
  234. void PostorderTraversal(vector<T>&result){
  235. __PostorderTraversal(root, result);
  236. }//后序遍历的外部接口
  237. void BFTraversal(vector<T>&result){
  238. return __BFTraversal(result);
  239. } //广度搜索外部接口
  240. void Graph(int indent,bstNode<T>* root){
  241. return __Graph(indent,root);
  242. } //横着画图的外部接口
  243. bstNode<T> * GetRoot(){
  244. return __GetRoot();
  245. } //返回根节点的外部接口
  246. };
  247. #endif //TEST1_MYBST_H

 

最后来进行测试:

main.cpp

  1. #include <iostream>
  2. #include <vector>
  3. #include "myBST.h"
  4. #include "bstNode.h"
  5. using namespace std;
  6. int main() {
  7. vector<int> in = {23,11,56,5,20,30,89,77,45,50};
  8. myBST<int> bst(in);
  9. bst.Delete(5);
  10. bst.Insert(4);
  11. bool found = bst.search(4);
  12. if(!found)
  13. cout<<"not found!"<<endl;
  14. else
  15. cout<<"found!"<<endl;
  16. vector<int> result;
  17. cout<<"InorderTravelsal: ";
  18. bst.InorderTraversal(result);
  19. cout<<endl<<"PreorderTravelsal: ";
  20. bst.PreorderTraversal(result);
  21. cout<<endl<<"PostorderTraversal: ";
  22. bst.PostorderTraversal(result);
  23. cout<<endl<<"BFTraversal: ";
  24. bst.BFTraversal(result);
  25. cout<<endl<<"Graph:"<<endl;
  26. bstNode<int>* pointer = bst.GetRoot();
  27. bst.Graph(0,pointer);
  28. return 0;
  29. }

得到图示结果:

参考:https://blog.csdn.net/zhangxiao93/article/details/51444972

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号