当前位置:   article > 正文

数据结构进阶 二叉搜索树详解_次优查找树找到根节点之后怎么往下找

次优查找树找到根节点之后怎么往下找

数据结构就是定义出某种结构:像数组结构、链表结构、树形结构等,实现数据结构就是我们主动去管理增删查改的实现函数 

二叉搜索树的概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树

非空左子树上所有节点的值都小于根节点的值,右子树上所有节点的值都大于根节点的值

二叉搜索树的定义

  1. template<class K>//搜索二叉树
  2. struct BSTreeNode
  3. {
  4. BSTreeNode<K>* _left;//左孩子指针
  5. BSTreeNode<K>* _right;//右孩子指针
  6. K _key;//节点数据值
  7. //构造函数
  8. BSTreeNode(const K& key):_left(nullptr),_right(nullptr),_key(key)
  9. {}
  10. };

先来了解一下文件BinnarySearchTree.h中的接口

  1. template<class K>
  2. class BSTree
  3. {
  4. typedef BSTreeNode<K> Node; //重命名上面的定义
  5. public
  6. //递归查找
  7. bool FindR(const K& key)
  8. {
  9. return _FindR(_root, key);
  10. }
  11. //递归插入
  12. bool InsertR(const K& key)
  13. {
  14. return _InsertR(_root, key);
  15. }
  16. //递归删除
  17. bool EraseR(const K& key)
  18. {
  19. return _EraseR(_root, key);
  20. }
  21. //中序遍历 类内调用拿root
  22. void InOrder()
  23. {
  24. _InOrder(_root);
  25. cout << endl;
  26. }
  27. //构造函数
  28. BSTree() = default;
  29. //拷贝构造
  30. BSTree(const BSTree<K>& t);
  31. //赋值函数
  32. BSTree<K>& operator=(BSTree<K> t);
  33. //析构函数
  34. ~BSTree();
  35. private:
  36. //类部子函数不继承的话通常私有
  37. bool _EraseR(Node*& root,const K& key);//递归删除
  38. bool _InsertR(Node*& root,const K& key);//递归插入
  39. bool _FindR(Node* root,const K& key);//递归查找
  40. void _InOrder(Node* root);//中序遍历函数
  41. void DestroyTree(Node* root)//置空函数
  42. Node* CopyTree(Node* root)//树的拷贝
  43. private:
  44. Node* _root = nullptr;
  45. };

下面我们来详细学习函数接口的具体实现

递归插入函数的定义

  1. //递归插入函数
  2. bool _InsertR(Node*& root,const K& key)//递归插入
  3. {
  4. if (root == nullptr)//为空就申请节点插入数据
  5. {
  6. root = new Node(key);//注意上面传指针引用 可以直接连接
  7. return true;
  8. }
  9. if (key > root->_key)//插入的值大于根 往右走
  10. {
  11. return _InsertR(root->_right, key);
  12. }
  13. else if (key < root->_key)//插入的值小于根 往右走
  14. {
  15. return _InsertR(root->_left, key);
  16. }
  17. else
  18. {
  19. return false;//相等说明数据已经有了
  20. }
  21. }

递归删除函数的定义

  1. bool _EraseR(Node*& root,const K& key)//递归删除
  2. {
  3. //先找到要删除的节点
  4. if (root == nullptr)//为空返回false
  5. {
  6. return false;
  7. }
  8. if (key > root->_key)//要删除的大于根
  9. {
  10. return _EraseR(root->_right, key);//递归右树找
  11. }
  12. else if (key < root->_key)//要删除的小于根
  13. {
  14. return _EraseR(root->_left, key);//递归左树找
  15. }
  16. //走到这里说明已经找到要删除的数据
  17. else
  18. {
  19. //1.删除一个孩子 左为空或右为空 托孤
  20. Node* del = root;//先保存要删除的节点
  21. if (root->_left == nullptr)//左为空 让父亲指向右
  22. {
  23. root = root->_right;//引用
  24. }
  25. else if (root->_right == nullptr)右为空 让父亲指向左
  26. {
  27. root = root->_left;
  28. }
  29. //2.删除2个孩子左右都不为空 替换法
  30. else
  31. {
  32. Node* minRight = root->_right;//
  33. while (minRight->_left)
  34. {
  35. minRight = minRight->_left;
  36. }
  37. swap(root->_key, minRight->_key);//交换数据
  38. //此时要删除的已经换下来 再去右树递归删除
  39. return _EraseR(root->_right, key);//指定树
  40. }
  41. delete del;
  42. return true;
  43. }
  44. }

中序遍历函数的定义

  1. //中序遍历
  2. void _InOrder(Node* root) 左子树 根 右子树
  3. {
  4. if (root == nullptr)
  5. return;
  6. _InOrder(root->_left);//先走左边
  7. cout << root->_key << " "; 打印数据
  8. _InOrder(root->_right);//后走右边
  9. }

  我们先用以上接口实现图中二叉树的插入和删除测试案例TestBSTree

  1. //递归插入测试
  2. void TestBSTree1()
  3. {
  4. //
  5. BSTree<int> t;
  6. int a[] = { 8,3,1,10,6,4,7,14,13, };
  7. for (auto e : a)
  8. {
  9. t.InsertR(e);//依次插入 默认去重
  10. }
  11. t.InOrder();//遍历打印 1 3 4 6 7 8 10 13 14
  12. }
  13. //递归删除测试
  14. void TestBSTree2()
  15. {
  16. //
  17. BSTree<int> t;
  18. int a[] = { 8,3,1,10,6,4,7,14,13, };
  19. for (auto e : a)
  20. {
  21. t.InsertR(e);//依次插入 默认去重
  22. }
  23. t.InOrder();//打印1 3 4 6 7 8 10 13 14
  24. t.EraseR(14);//删除14
  25. t.InOrder();//打印1 3 4 6 7 8 10 13
  26. }
  27. int main()
  28. {
  29. TestBSTree1();//递归插入
  30. TestBSTree2();//递归删除
  31. return 0;
  32. }

递归查找函数的定义

从根开始比较查找,比根大则往右边查找,比根小则往左边查找

  1. bool _FindR(Node* root,const K& key)//递归查找
  2. {
  3. if (root == nullptr)
  4. return false;
  5. if (key > root->_key)//
  6. {
  7. return _FindR(root->_right, key);
  8. }
  9. else if(key < root->_key)
  10. {
  11. return _FindR(root->_left, key);
  12. }
  13. else
  14. {
  15. return true;//相等就找到了
  16. }
  17. }

置空函数定义

置空函数一般会放在我们进行插入或删除的函数最后,释放我们在堆上申请的空间,将其还给操作系统,另外也会相应的进行检查越界等问题

  1. void DestroyTree(Node* root)//置空函数
  2. {
  3. if (root == nullptr)
  4. return;
  5. DestroyTree(root->_left);
  6. DestroyTree(root->_right);
  7. delete root;
  8. }

析构函数定义

  1. ~BSTree()//析构函数
  2. {
  3. DestroyTree(_root);//调用置空函数
  4. _root = nullptr;
  5. }

赋值函数定义

  1. BSTree<K>& operator=(BSTree<K> t)//赋值函数
  2. {
  3. swap(_root, t._root);
  4. return *this;
  5. }

树的拷贝函数定义

  1. Node* CopyTree(Node* root)//拷贝树
  2. {
  3. if (root == nullptr)
  4. return nullptr;
  5. Node* copynode = new Node(root->_key);
  6. copynode->_left = CopyTree(root->_left);//递归创建左树
  7. copynode->_right = CopyTree(root->_right);//递归创建右树
  8. return copynode;
  9. }

拷贝构造函数定义

  1. BSTree(const BSTree<K>& t)//拷贝构造
  2. {
  3. _root = CopyTree(t._root);//调用下方树的拷贝函数
  4. cout << "调用拷贝构造" << endl;
  5. }

我们再用上面这几个接口实现第3个测试案例TestBSTree3

  1. //赋值函数测试
  2. void TestBSTree3()
  3. {
  4. //
  5. BSTree<int> t;
  6. int a[] = { 8,3,1,10,6,4,7,14,13, };
  7. for (auto e : a)
  8. {
  9. t.InsertR(e);//依次插入 默认去重
  10. }
  11. t.InOrder();//遍历打印 1 3 4 6 7 8 10 13 14
  12. BSTree<int> t1;
  13. t1 = t;//赋值函数 调用拷贝构造
  14. t.InOrder();//遍历打印1 3 4 6 7 8 10 13 14
  15. }
  16. int main()
  17. {
  18. TestBSTree3();//赋值函数测试
  19. return 0;
  20. }

最后这里放一下整个二叉搜索树递归版本代码的实现,方便大家观察理解

  1. #pragma once
  2. template<class K>//搜索二叉树
  3. struct BSTreeNode
  4. {
  5. BSTreeNode<K>* _left;
  6. BSTreeNode<K>* _right;
  7. K _key;
  8. //构造函数
  9. BSTreeNode(const K& key):_left(nullptr),_right(nullptr),_key(key)
  10. {}
  11. };
  12. template<class K>
  13. class BSTree
  14. {
  15. typedef BSTreeNode<K> Node;
  16. public:
  17. //默认构造
  18. BSTree() = default;
  19. //拷贝构造
  20. BSTree(const BSTree<K>& t)
  21. {
  22. _root = CopyTree(t._root);
  23. cout << "调用拷贝构造" << endl;
  24. }
  25. //赋值函数
  26. BSTree<K>& operator=(BSTree<K> t)
  27. {
  28. swap(_root, t._root);
  29. return *this;
  30. }
  31. //析构函数
  32. ~BSTree()
  33. {
  34. DestroyTree(_root);
  35. _root = nullptr;
  36. }
  37. //递归查找
  38. bool FindR(const K& key)
  39. {
  40. return _FindR(_root, key);
  41. }
  42. //递归插入
  43. bool InsertR(const K& key)
  44. {
  45. return _InsertR(_root, key);
  46. }
  47. //递归删除
  48. bool EraseR(const K& key)
  49. {
  50. return _EraseR(_root, key);
  51. }
  52. //中序遍历 类内调用拿root
  53. void InOrder()
  54. {
  55. _InOrder(_root);
  56. cout << endl;
  57. }
  58. private://类部子函数不继承的话通常私有
  59. //递归删除
  60. bool _EraseR(Node*& root,const K& key)
  61. {
  62. if (root == nullptr)
  63. {
  64. return false;
  65. }
  66. if (key > root->_key)//
  67. {
  68. return _EraseR(root->_right, key);
  69. }
  70. else if (key < root->_key)
  71. {
  72. return _EraseR(root->_left, key);
  73. }
  74. else
  75. {
  76. Node* del = root;//保存要删除的节点
  77. //相等说明可以删除了 三种情况
  78. if (root->_left == nullptr)
  79. {
  80. root = root->_right;//引用
  81. }
  82. else if (root->_right == nullptr)
  83. {
  84. root = root->_left;
  85. }
  86. else//左右都不为空 替换法
  87. {
  88. Node* minRight = root->_right;
  89. while (minRight->_left)
  90. {
  91. minRight = minRight->_left;
  92. }
  93. swap(root->_key, minRight->_key);//交换数据
  94. //此时要删除的已经换下来 再去右树递归删除
  95. return _EraseR(root->_right, key);//指定树
  96. }
  97. delete del;
  98. return true;
  99. }
  100. }
  101. bool _InsertR(Node*& root,const K& key)//递归插入
  102. {
  103. if (root == nullptr)//为空就申请节点插入数据
  104. {
  105. root = new Node(key);//注意上面传指针引用 可以直接连接
  106. return true;
  107. }
  108. if (key > root->_key)//插入的值大于根 往右走
  109. {
  110. return _InsertR(root->_right, key);
  111. }
  112. else if (key < root->_key)//插入的值小于根 往右走
  113. {
  114. return _InsertR(root->_left, key);
  115. }
  116. else
  117. {
  118. return false;//相等说明数据已经有了
  119. }
  120. }
  121. bool _FindR(Node* root,const K& key)//递归查找
  122. {
  123. //
  124. if (root == nullptr)
  125. return false;
  126. if (key > root->_key)//
  127. {
  128. return _FindR(root->_right, key);
  129. }
  130. else if(key < root->_key)
  131. {
  132. return _FindR(root->_left, key);
  133. }
  134. else
  135. {
  136. return true;//相等就找到了
  137. }
  138. }
  139. void _InOrder(Node* root)//中序遍历
  140. {
  141. if (root == nullptr)
  142. return;
  143. _InOrder(root->_left);
  144. cout << root->_key << " ";
  145. _InOrder(root->_right);
  146. }
  147. void DestroyTree(Node* root)//置空函数
  148. {
  149. if (root == nullptr)
  150. return;
  151. DestroyTree(root->_left);
  152. DestroyTree(root->_right);
  153. delete root;
  154. }
  155. Node* CopyTree(Node* root)//拷贝树
  156. {
  157. if (root == nullptr)
  158. return nullptr;
  159. Node* copynode = new Node(root->_key);
  160. copynode->_left = CopyTree(root->_left);//递归创建左树
  161. copynode->_right = CopyTree(root->_right);//递归创建右树
  162. return copynode;
  163. }
  164. private:
  165. Node* _root = nullptr;
  166. };
  167. //递归插入测试
  168. void TestBSTree1()
  169. {
  170. BSTree<int> t;
  171. int a[] = { 8,3,1,10,6,4,7,14,13, };
  172. for (auto e : a)
  173. {
  174. t.InsertR(e);//依次插入 默认去重
  175. }
  176. t.InOrder();//遍历
  177. }
  178. //递归删除测试
  179. void TestBSTree2()
  180. {
  181. BSTree<int> t;
  182. int a[] = { 8,3,1,10,6,4,7,14,13, };
  183. for (auto e : a)
  184. {
  185. t.InsertR(e);//依次插入 默认去重
  186. }
  187. t.InOrder();//打印 1 3 4 6 7 8 10 13 14
  188. t.EraseR(8);//删除8
  189. t.EraseR(3);//删除3
  190. t.InOrder();//打印 1 4 6 7 10 13 14
  191. }
  192. //赋值函数测试
  193. void TestBSTree3()
  194. {
  195. BSTree<int> t;
  196. int a[] = { 8,3,1,10,6,4,7,14,13, };
  197. for (auto e : a)
  198. {
  199. t.InsertR(e);//依次插入 默认去重
  200. }
  201. t.InOrder();//遍历打印 1 3 4 6 7 8 10 13 14
  202. BSTree<int> t1;
  203. t1 = t;//赋值函数 调用拷贝构造
  204. t.InOrder();//遍历打印1 3 4 6 7 8 10 13 14
  205. }
  206. int main()
  207. {
  208. TestBSTree1();//插入函数测试
  209. TestBSTree2();//删除函数测试
  210. TestBSTree3();//赋值函数测试
  211. return 0;
  212. }

在Java和C++的学习当中,前期学习数据结构当中的顺序表、链表、二叉树等便于我们后面更好的学习容器,后面会继续分享红黑树和排序的实现

希望这篇文章大家有所收获,我们下篇见

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号