当前位置:   article > 正文

二叉搜索树详解及代码实现_二叉搜索树代码

二叉搜索树代码

目录

一、什么是二叉搜索树

 二、二叉搜索树的有关操作

2.1 查找:

2.2插入:

2.3 删除:

 2.4 打印

三、二叉搜索树的应用

3.1 K模型:

3.2 KV模型:

四、整体代码:

K模型:

KV模型:


一、什么是二叉搜索树

二叉搜索树(BST, Binary Search Tree),也称为二叉排序树或二叉查找树。

每一棵搜索树都满足如下条件:

1.非空左子树的所有键值小于其根节点的键值

2.非空右子树的所有键值大于其根节点的键值

3.左、右子树都是二叉搜索树

 如图所示二叉树:

 二、二叉搜索树的有关操作

如该树 数组表示为:int a[] = {8, 3, 1, 10, 6, 4, 7, 14, 13}; 用此树进行讲解

下面代码用到的c++类结构为:

  1. template<class K> //模板
  2. struct BSTreeNode {
  3. BSTreeNode<K>* _left;
  4. BSTreeNode<K>* _right;
  5. K _key;
  6. private:
  7. Node* _root = nullptr;
  8. };

2.1 查找:

a、从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。
b、最多查找高度次,走到到空,还没找到,这个值不存在。

代码实现:

非递归:

  1. bool Find(const K& key) //K为模板
  2. {
  3. Node* cur = _root;
  4. while (cur)
  5. {//遍历,大于根往右,小于往左,相等就结束,遍历完没找到就是没找到
  6. if (cur->_key < key)
  7. {
  8. cur = cur->_right;
  9. }
  10. else if (cur->_key > key)
  11. {
  12. cur = cur->_left;
  13. }
  14. else
  15. {
  16. return true;
  17. }
  18. }
  19. return false;
  20. }

递归:

  1. bool _FindR(Node* root, const K& key)
  2. {
  3. if (root == nullptr)
  4. return false;
  5. if (root->_key < key)
  6. return _FinfR(root->_right, key);
  7. else if (root->_key > key)
  8. return _FindR(root->_left, key);
  9. else
  10. return true;
  11. }

2.2插入:

插入的具体过程如下:
a. 树为空,则直接新增节点,赋值给root指针
b. 树不空,按二叉搜索树性质查找插入位置,插入新节点(大于根节点值往右走,小于根节点值往左走)。注意:二叉搜索树插入过程中,插入已存在值无意义。

为该树插入16 、9 两个值,根据搜素树应满足的“左小右大”的条件,插入后如图:

 代码实现:

非递归写法:

  1. bool Insert(const K& key) //K为模板
  2. {
  3. //空树直接插
  4. if (_root == nullptr)
  5. {
  6. _root = new Node(key);
  7. return true;
  8. }
  9. //非空树
  10. Node* parent = nullptr;//用于存父节点,便于与插入的子节点链接
  11. Node* cur = _root;
  12. while (cur)//找到要插入的位置
  13. {
  14. if (cur->_key < key)//大于 往右子树
  15. {
  16. parent = cur;
  17. cur = cur->_right;
  18. }
  19. else if (cur->_key > key)//小于往左子树
  20. {
  21. parent = cur;
  22. cur = cur->_left;
  23. }
  24. else
  25. {
  26. return false;//遇到相同的数就不插入,相当于去重
  27. }
  28. }
  29. //找到插入的位置后,进行插入操作
  30. cur = new Node(key);
  31. if (parent->_key < key)
  32. {
  33. parent->_right = cur;
  34. }
  35. else
  36. {
  37. parent->_left = cur;
  38. }
  39. return true;
  40. }

递归写法:

  1. bool _InsertR(Node*& root, const K& key) //K为模板
  2. {
  3. if (root == nullptr)
  4. {
  5. root = new Node(key);
  6. return true;
  7. }
  8. if (root->_key < key)
  9. {
  10. return _InsertR(root->_right, key);
  11. }
  12. else if (root->_key > key)
  13. {
  14. return _InsertR(root->_left, key);
  15. }
  16. else
  17. {
  18. return false;
  19. }
  20. }

2.3 删除:

删除某一节点可分为四种情况:

a.要删除节点没有孩子节点

如图删除节点值13,没有孩子节点,删除后父节点parent->left就指向空。

 b.要删除的结点只有左孩子结点 

c. 要删除的结点只有右孩子结点

该两种情况相似。如删除节点14后,其孩子节点13的父节点就变为10,即:10->right=13

d. 要删除的结点有左、右孩子结点

该情况难点在于删除节点后,被删除节点的父节点应该链接被删除节点的哪个孩子节点。这分为两种方法:

1.连接删除节点的左子树中最右边节点

2.连接删除节点的右子树中最左节点

一般情况下,我们使用方法2.在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题--替换法删除


 代码实现:
非递归:

  1. bool Erase(const K& key)
  2. {
  3. Node* parent = nullptr;
  4. Node* cur = _root;
  5. while (cur)
  6. {
  7. if (cur->_key < key)
  8. {
  9. parent = cur;
  10. cur = cur->_right;
  11. }
  12. else if (cur->_key > key)
  13. {
  14. parent = cur;
  15. cur = cur->_left;
  16. }
  17. else
  18. {
  19. //开始删除
  20. //删除位置左空
  21. if (cur->_left == nullptr)
  22. {
  23. if (cur == _root)//删除位置在根处
  24. {
  25. _root = cur->_right;
  26. }
  27. else
  28. {
  29. //找到当前位置后且左空,且位于parent的左,
  30. //则删除该位置后的parent左就变为cur的右
  31. //如果当前位置位于parren右,且且左空,则paret的右即为cur的右
  32. if (cur == parent->_left)
  33. {
  34. parent->_left = cur->_right;
  35. }
  36. else
  37. {
  38. parent->_right = cur->_right;
  39. }
  40. }
  41. delete cur;
  42. cur == nullptr;
  43. }
  44. else if (cur->_right == nullptr)//删除位置右空
  45. {
  46. if (cur == _root)
  47. {
  48. _root = cur->_left;
  49. }
  50. else
  51. {
  52. if (cur == parent->_left)
  53. {
  54. parent->_left = cur->_left;
  55. }
  56. else
  57. {
  58. parent->_right = cur->_left;
  59. }
  60. }
  61. delete cur;
  62. cur = nullptr;
  63. }
  64. else//左右都不为空
  65. {
  66. //替换法删除 //右子树最小节点---右子树最左节点
  67. Node* minparent = cur;
  68. Node* min = cur->_right;
  69. while (min->_left)
  70. {
  71. minparent = min;
  72. min = min->_left;
  73. }
  74. swap(cur->_key, min->_key);
  75. if (minparent->_left == min)
  76. minparent->_left = min->_right;
  77. else
  78. minparent->_right = min->_right;
  79. delete min;
  80. }
  81. return true;
  82. }
  83. }
  84. return false;
  85. }

递归:

  1. bool _EraseR(Node*& root, const K& key)
  2. {
  3. if (root == nullptr)
  4. {
  5. return false;
  6. }
  7. if (root->_key < key)
  8. {
  9. return _EraseR(root->_right, key);
  10. }
  11. else if (root->_key > key)
  12. {
  13. return _EraseR(root->_left, key);
  14. }
  15. else
  16. {
  17. Node* del = root;
  18. if (root->_left == nullptr)
  19. {
  20. root = root->_right;
  21. }
  22. else if (root->_right == nullptr)
  23. {
  24. root = root->_left;
  25. }
  26. else
  27. {
  28. //找右数的最左节点
  29. Node* min = root->_right;
  30. while (min->_left)
  31. {
  32. min = min->_left;
  33. }
  34. swap(root->_key, min->_key);
  35. return _EraseR(root->_right, key);
  36. }
  37. delete del;
  38. return true;
  39. }
  40. }

 2.4 打印

这里可以将创建的二叉搜索树通过中序(左->根->右)打印出来,就是由小到大的升序序列。因为二叉搜索树中不能有重复的数值,所以可以通过插入一组数据实现对其排序且去重。

  1. void _InOrder(Node* root)
  2. {
  3. if (root == nullptr)
  4. {
  5. return;
  6. }
  7. _InOrder(root->_left);
  8. cout << root->_key << " ";
  9. _InOrder(root->_right);
  10. }

该二叉搜索树的整体代码放在文末。

三、二叉搜索树的应用

3.1 K模型:

上面我们所实现的就是K模型。

K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到
的值。
比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:
以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树,在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误

3.2 KV模型:

KV模型:每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。一般可以通过查找关键码key来查找对应的值。

比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英
文单词与其对应的中文<word, chinese>就构成一种键值对。(KV模型整体代码与K模型思想很相似,就直接放在文末)

  1. void TestBSTree1()
  2. {
  3. BSTree<string, string> dict;
  4. dict.Insert("sort", "排序");
  5. dict.Insert("left", "左边");
  6. dict.Insert("right", "右边");
  7. dict.Insert("string", "字符串");
  8. dict.Insert("insert", "插入");
  9. string str;
  10. while (cin >> str)
  11. {
  12. BSTreeNode<string, string>* ret = dict.Find(str);
  13. if (ret)
  14. {
  15. cout << ":" << ret->_value << endl;
  16. }
  17. else
  18. {
  19. cout << "->无此单词" << endl;
  20. }
  21. }
  22. }

 再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出
现次数就是<word, count>就构成一种键值对。

  1. void TestBSTree2()
  2. {
  3. string arr[] = { "苹果","苹果" ,"香蕉" ,"草莓" ,"香蕉" ,"苹果" ,"苹果", "苹果" };
  4. BSTree<string, int> countTree;
  5. for (auto& str:arr)
  6. {
  7. auto ret = countTree.Find(str);
  8. if (ret)
  9. {
  10. ret->_value++;
  11. }
  12. else
  13. {
  14. countTree.Insert(str, 1);
  15. }
  16. }
  17. countTree.InOrder();
  18. }

四、整体代码:

K模型:

  1. namespace key
  2. {
  3. template<class K>
  4. struct BSTreeNode {
  5. BSTreeNode<K>* _left;
  6. BSTreeNode<K>* _right;
  7. K _key;
  8. BSTreeNode(const K& key)
  9. :_left(nullptr)
  10. , _right(nullptr)
  11. , _key(key)
  12. {}
  13. };
  14. //BinarySearchTree
  15. template<class K> //Key
  16. class BSTree {
  17. typedef BSTreeNode<K> Node;
  18. public:
  19. bool Insert(const K& key)
  20. {
  21. if (_root == nullptr)
  22. {
  23. _root = new Node(key);
  24. return true;
  25. }
  26. Node* parent = nullptr;
  27. Node* cur = _root;
  28. while (cur)//找到要插入的位置
  29. {
  30. if (cur->_key < key)
  31. {
  32. parent = cur;
  33. cur = cur->_right;
  34. }
  35. else if (cur->_key > key)
  36. {
  37. parent = cur;
  38. cur = cur->_left;
  39. }
  40. else
  41. {
  42. return false;//遇到相同的数就不插入,相当于去重
  43. }
  44. }
  45. cur = new Node(key);
  46. if (parent->_key < key)
  47. {
  48. parent->_right = cur;
  49. }
  50. else
  51. {
  52. parent->_left = cur;
  53. }
  54. return true;
  55. }
  56. bool Find(const K& key)
  57. {
  58. Node* cur = _root;
  59. while (cur)
  60. {
  61. if (cur->_key < key)
  62. {
  63. cur = cur->_right;
  64. }
  65. else if (cur->_key > key)
  66. {
  67. cur = cur->_left;
  68. }
  69. else
  70. {
  71. return true;
  72. }
  73. }
  74. return false;
  75. }
  76. bool Erase(const K& key)
  77. {
  78. Node* parent = nullptr;
  79. Node* cur = _root;
  80. while (cur)
  81. {
  82. if (cur->_key < key)
  83. {
  84. parent = cur;
  85. cur = cur->_right;
  86. }
  87. else if (cur->_key > key)
  88. {
  89. parent = cur;
  90. cur = cur->_left;
  91. }
  92. else
  93. {
  94. //开始删除
  95. //删除位置左空
  96. if (cur->_left == nullptr)
  97. {
  98. if (cur == _root)//删除位置在根处
  99. {
  100. _root = cur->_right;
  101. }
  102. else
  103. {
  104. //找到当前位置后且左空,且位于parent的左,
  105. //则删除该位置后的parent左就变为cur的右
  106. //如果当前位置位于parren右,且且左空,则paret的右即为cur的右
  107. if (cur == parent->_left)
  108. {
  109. parent->_left = cur->_right;
  110. }
  111. else
  112. {
  113. parent->_right = cur->_right;
  114. }
  115. }
  116. delete cur;
  117. cur == nullptr;
  118. }
  119. else if (cur->_right == nullptr)//删除位置右空
  120. {
  121. if (cur == _root)
  122. {
  123. _root = cur->_left;
  124. }
  125. else
  126. {
  127. if (cur == parent->_left)
  128. {
  129. parent->_left = cur->_left;
  130. }
  131. else
  132. {
  133. parent->_right = cur->_left;
  134. }
  135. }
  136. delete cur;
  137. cur = nullptr;
  138. }
  139. else//左右都不为空
  140. {
  141. //替换法删除 //右子树最小节点---右子树最左节点
  142. Node* minparent = cur;
  143. Node* min = cur->_right;
  144. while (min->_left)
  145. {
  146. minparent = min;
  147. min = min->_left;
  148. }
  149. swap(cur->_key, min->_key);
  150. if (minparent->_left == min)
  151. minparent->_left = min->_right;
  152. else
  153. minparent->_right = min->_right;
  154. delete min;
  155. }
  156. return true;
  157. }
  158. }
  159. return false;
  160. }
  161. void InOrder()
  162. {
  163. _InOrder(_root);//这里套一层就可以直接使用_root;或者也可以写getroot方法
  164. cout << endl;
  165. }
  166. //递归查找
  167. bool FindR(const K& key)
  168. {
  169. return _FindR(_root, key);
  170. }
  171. //递归插
  172. bool InsertR(const K& key)
  173. {
  174. return _InsertR(_root, key);
  175. }
  176. //递归删
  177. bool EraseR(const K& key)
  178. {
  179. return _EraseR(_root, key);
  180. }
  181. ~BSTree()
  182. {
  183. _Destroy(_root);
  184. }
  185. //强制编译器生成默认的构造
  186. BSTree() = default;
  187. BSTree(const BSTree<K>& t)
  188. {
  189. _root = _copy(t._root);
  190. }
  191. BSTree<K>& operator=(BSTree<K> t)
  192. {
  193. swap(_root, t._root);
  194. return *this;
  195. }
  196. private:
  197. Node* _copy(Node* root)
  198. {
  199. if (root == nullptr)
  200. {
  201. return nullptr;
  202. }
  203. Node* copyRoot = new Node(root->_key);
  204. copyRoot->_left = _copy(root->_left);
  205. copyRoot->_right = _copy(root->_right);
  206. return copyRoot;
  207. }
  208. void _Destroy(Node*& root)
  209. {
  210. if (root == nullptr)
  211. {
  212. return;
  213. }
  214. _Destroy(root->_left);
  215. _Destroy(root->_right);
  216. delete root;
  217. root = nullptr;
  218. }
  219. bool _EraseR(Node*& root, const K& key)
  220. {
  221. if (root == nullptr)
  222. {
  223. return false;
  224. }
  225. if (root->_key < key)
  226. {
  227. return _EraseR(root->_right, key);
  228. }
  229. else if (root->_key > key)
  230. {
  231. return _EraseR(root->_left, key);
  232. }
  233. else
  234. {
  235. Node* del = root;
  236. if (root->_left == nullptr)
  237. {
  238. root = root->_right;
  239. }
  240. else if (root->_right == nullptr)
  241. {
  242. root = root->_left;
  243. }
  244. else
  245. {
  246. //找右数的最左节点
  247. Node* min = root->_right;
  248. while (min->_left)
  249. {
  250. min = min->_left;
  251. }
  252. swap(root->_key, min->_key);
  253. return _EraseR(root->_right, key);//很巧妙
  254. }
  255. delete del;
  256. return true;
  257. }
  258. }
  259. bool _InsertR(Node*& root, const K& key)
  260. {
  261. if (root == nullptr)
  262. {
  263. root = new Node(key);
  264. return true;
  265. }
  266. if (root->_key < key)
  267. {
  268. return _InsertR(root->_right, key);
  269. }
  270. else if (root->_key > key)
  271. {
  272. return _InsertR(root->_left, key);
  273. }
  274. else
  275. {
  276. return false;
  277. }
  278. }
  279. bool _FindR(Node* root, const K& key)
  280. {
  281. if (root == nullptr)
  282. return false;
  283. if (root->_key < key)
  284. return _FinfR(root->_right, key);
  285. else if (root->_key > key)
  286. return _FindR(root->_left, key);
  287. else
  288. return true;
  289. }
  290. //中序 //
  291. void _InOrder(Node* root)
  292. {
  293. if (root == nullptr)
  294. {
  295. return;
  296. }
  297. _InOrder(root->_left);
  298. cout << root->_key << " ";
  299. _InOrder(root->_right);
  300. }
  301. private:
  302. Node* _root = nullptr;
  303. };
  304. }

KV模型:

  1. template<class K,class V>
  2. struct BSTreeNode {
  3. BSTreeNode<K,V>* _left;
  4. BSTreeNode<K,V>* _right;
  5. K _key;
  6. V _value;
  7. BSTreeNode(const K& key, const V& value)
  8. :_left(nullptr)
  9. , _right(nullptr)
  10. , _key(key)
  11. , _value(value)
  12. {}
  13. };
  14. template<class K,class V> //
  15. class BSTree {
  16. typedef BSTreeNode<K,V> Node;
  17. public:
  18. bool Insert(const K& key,const V& value)
  19. {
  20. if (_root == nullptr)
  21. {
  22. _root = new Node(key,value);
  23. return true;
  24. }
  25. Node* parent = nullptr;
  26. Node* cur = _root;
  27. while (cur)//找到要插入的位置
  28. {
  29. if (cur->_key < key)
  30. {
  31. parent = cur;
  32. cur = cur->_right;
  33. }
  34. else if (cur->_key > key)
  35. {
  36. parent = cur;
  37. cur = cur->_left;
  38. }
  39. else
  40. {
  41. return false;//遇到相同的数就不插入,相当于去重
  42. }
  43. }
  44. cur = new Node(key,value);
  45. if (parent->_key < key)
  46. {
  47. parent->_right = cur;
  48. }
  49. else
  50. {
  51. parent->_left = cur;
  52. }
  53. return true;
  54. }
  55. Node* Find(const K& key)
  56. {
  57. Node* cur = _root;
  58. while (cur)
  59. {
  60. if (cur->_key < key)
  61. {
  62. cur = cur->_right;
  63. }
  64. else if (cur->_key > key)
  65. {
  66. cur = cur->_left;
  67. }
  68. else
  69. {
  70. return cur;
  71. }
  72. }
  73. return nullptr;
  74. }
  75. bool Erase(const K& key)
  76. {
  77. Node* parent = nullptr;
  78. Node* cur = _root;
  79. while (cur)
  80. {
  81. if (cur->_key < key)
  82. {
  83. parent = cur;
  84. cur = cur->_right;
  85. }
  86. else if (cur->_key > key)
  87. {
  88. parent = cur;
  89. cur = cur->_left;
  90. }
  91. else
  92. {
  93. //开始删除
  94. //删除位置左空
  95. if (cur->_left == nullptr)
  96. {
  97. if (cur == _root)//删除位置在根处
  98. {
  99. _root = cur->_right;
  100. }
  101. else
  102. {
  103. //找到当前位置后且左空,且位于parent的左,
  104. //则删除该位置后的parent左就变为cur的右
  105. //如果当前位置位于parren右,且且左空,则paret的右即为cur的右
  106. if (cur == parent->_left)
  107. {
  108. parent->_left = cur->_right;
  109. }
  110. else
  111. {
  112. parent->_right = cur->_right;
  113. }
  114. }
  115. delete cur;
  116. cur == nullptr;
  117. }
  118. else if (cur->_right == nullptr)//删除位置右空
  119. {
  120. if (cur == _root)
  121. {
  122. _root = cur->_left;
  123. }
  124. else
  125. {
  126. if (cur == parent->_left)
  127. {
  128. parent->_left = cur->_left;
  129. }
  130. else
  131. {
  132. parent->_right = cur->_left;
  133. }
  134. }
  135. delete cur;
  136. cur = nullptr;
  137. }
  138. else//左右都不为空
  139. {
  140. //替换法删除 //右子树最小节点---右子树最左节点
  141. Node* minparent = cur;
  142. Node* min = cur->_right;
  143. while (min->_left)
  144. {
  145. minparent = min;
  146. min = min->_left;
  147. }
  148. swap(cur->_key, min->_key);
  149. if (minparent->_left == min)
  150. minparent->_left = min->_right;
  151. else
  152. minparent->_right = min->_right;
  153. delete min;
  154. }
  155. return true;
  156. }
  157. }
  158. //删除的中间过程都一样
  159. return true;
  160. }
  161. void InOrder()
  162. {
  163. _InOrder(_root);//这里套一层就可以直接使用_root;或者也可以写getroot方法
  164. cout << endl;
  165. }
  166. private:
  167. //中序 //
  168. void _InOrder(Node* root)
  169. {
  170. if (root == nullptr)
  171. {
  172. return;
  173. }
  174. _InOrder(root->_left);
  175. cout << root->_key << " value: " << root->_value << endl;;
  176. _InOrder(root->_right);
  177. }
  178. private:
  179. Node* _root = nullptr;
  180. };

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/910098
推荐阅读
相关标签
  

闽ICP备14008679号