1 #include <iostream>
2 using namespace std;
3
4 struct node
5 {
6 // 数据域
7 int data;
8
9 // 左节点
10 node *lc;
11
12 // 右结点
13 node *rc;
14
15 // 构造函数
16 node()
17 : data(0)
18 , lc(NULL)
19 , rc(NULL)
20 {
21 }
22 };
23
24
25 // bst
26 class bstree
27 {
28 public:
29 enum
30 {
31 hmax_size_32767 = 32767,
32 hmin_size_0 = 0,
33 };
34
35 public:
36
37 // 构造函数
38 bstree()
39 : root(NULL)
40 , size(0)
41 {
42 }
43
44 // 析构函数
45 virtual ~bstree(){}
46
47 int get_size()
48 {
49 return size;
50 }
51
52 // 插入结点
53 void insert_node(int data)
54 {
55 int cur_size = get_size();
56 if (hmax_size_32767 == cur_size)
57 {
58 cout << "insert node error, the size of the tree is max" << endl;
59 return ;
60 }
61 root = insert(root, data);
62 }
63
64 // 先序遍历(前序遍历)
65 void pre_order()
66 {
67 pre_order_traverse(root);
68 }
69
70 // 中序遍历
71 void in_order()
72 {
73 in_order_traverse(root);
74 }
75
76 // 后序遍历
77 void post_order()
78 {
79 post_order_traverse(root);
80 }
81
82 /*
83 查找某个结点
84 int key - 查找结果
85
86 返回值:
87 NULL : 可能为root为空 或者 没有找到
88 != NULL, 找到结点
89 */
90 node* query(int key)
91 {
92 if (NULL == root)
93 {
94 cout << "query error, root = null" << endl;
95 return NULL;
96 }
97
98 return query_node(root, key);
99 }
100
101 // 删除树
102 void remove_all()
103 {
104 if (NULL == root)
105 {
106 cout << "remove all failed, root = null" << endl;
107 return;
108 }
109
110 remove_all(root);
111
112 int cur_size = get_size();
113 if (0 == cur_size)
114 root = NULL;
115 }
116
117 // 删除某个结点
118 void remove_node(int del_data)
119 {
120 if (NULL == root)
121 {
122 cout << "remove node error, root = null" << endl;
123 return;
124 }
125
126 node *parent_node = NULL;
127 node *del_node = root;
128
129 // 找到删除结点的父节点与删除结点
130 while (del_node)
131 {
132 if (del_data == del_node->data)
133 break;
134 else if (del_data > del_node->data)
135 {
136 parent_node = del_node;
137 del_node = del_node->rc;
138 }
139 else if (del_data < del_node->data)
140 {
141 parent_node = del_node;
142 del_node = del_node->lc;
143 }
144 }
145
146 // 若没有找到要删除的结点
147 if (NULL == del_node)
148 {
149 cout << "remove node error, " << del_data << " was not find" << endl;
150 return;
151 }
152
153 // 1、若删除的结点没有左子树和右子树
154 if ( (NULL == del_node->lc) && (NULL == del_node->rc) )
155 {
156 // 为什么要先判断根结点,因为根结点的父节点找不到,结果为NULL,
157 // 1.1 可能只有一个根结点, 将root释放值为空
158 if (del_node == root)
159 {
160 root = NULL;
161 delete del_node;
162 del_node = NULL;
163
164 dec_size();
165 return;
166 }
167
168 // 1.2 非根结点,那就是叶子结点了, 将父节点指向删除结点的分支指向NULL
169 if (del_node == parent_node->lc)
170 parent_node->lc = NULL;
171 else if (del_node == parent_node->rc)
172 parent_node->rc = NULL;
173
174 // 释放结点
175 delete del_node;
176 del_node = NULL;
177 dec_size();
178 }
179
180 // 2、若删除结点只有左孩子,没有右孩子
181 else if ( (NULL != del_node->lc) && (NULL == del_node->rc) )
182 {
183 // 2.1 删除结点为根结点,则将删除结点的左孩子替代当前删除结点
184 if (del_node == root)
185 {
186 root = root->lc;
187 }
188 // 2.2 其他结点,将删除结点的左孩子作为父节点的左孩子
189 else
190 {
191 if (parent_node->lc == del_node)
192 parent_node->lc = del_node->lc;
193 else if (parent_node->rc == del_node)
194 parent_node->rc = del_node->lc;
195 }
196
197 delete del_node;
198 del_node = NULL;
199
200 dec_size();
201 }
202
203 // 3、若删除结点只有右孩子
204 else if ( (NULL == del_node->lc) && (NULL != del_node->rc) )
205 {
206 // 3.1 若为根结点
207 if (root == del_node)
208 {
209 root = root->rc;
210 }
211 else
212 {
213 if (del_node == parent_node->lc)
214 parent_node->lc = del_node->rc;
215 else if (del_node == parent_node->rc)
216 parent_node->rc = del_node->rc;
217 }
218
219 delete del_node;
220 del_node = NULL;
221
222 dec_size();
223 }
224
225 // 4、若删除结点既有左孩子,又有右孩子,需要找到删除结点的后继结点作为根结点
226 else if ( (NULL != del_node->lc) && (NULL != del_node->rc) )
227 {
228 node *successor_node = del_node->rc;
229 parent_node = del_node;
230
231 while (successor_node->lc)
232 {
233 parent_node = successor_node;
234 successor_node = successor_node->lc;
235 }
236
237 // 交换后继结点与当前删除结点的数据域
238 del_node->data = successor_node->data;
239 // 将指向后继结点的父节点的孩子设置后继结点的右子树
240 if (successor_node == parent_node->lc)
241 parent_node->lc = successor_node->rc;
242 else if (successor_node == parent_node->rc)
243 parent_node->rc = successor_node->rc;
244
245 // 删除后继结点
246 del_node = successor_node;
247 delete del_node;
248 del_node = NULL;
249
250 dec_size();
251 }
252 }
253
254 // 返回以proot为根结点的最小结点
255 node *get_min_node(node *proot)
256 {
257 if (NULL == proot->lc)
258 return proot;
259
260 return get_min_node(proot->lc);
261 }
262
263 // 返回以proo为根节点的最大结点
264 node *get_max_node(node *proot)
265 {
266 if (NULL == proot->rc)
267 return proot;
268
269 return get_max_node(proot->rc);
270 }
271
272 // 返回根节点
273 node *get_root_node()
274 {
275 return root;
276 }
277
278 // 返回proot结点的父节点
279 node *get_parent_node(int key)
280 {
281 // 当前结点
282 node *cur_node = NULL;
283 // 父节点
284 node *parent_node = NULL;
285
286 cur_node = root;
287
288 // 标记是否找到
289 bool is_find = false;
290 while (cur_node)
291 {
292 if (key == cur_node->data)
293 {
294 is_find = true;
295 break;
296 }
297
298 // 因为比当前结点的值还要小,所以需要查找当前结点的左子树
299 else if (key < cur_node->data)
300 {
301 parent_node = cur_node;
302 cur_node = cur_node->lc;
303 }
304 // 同上, 查找当前结点的右子树
305 else if (key > cur_node->data)
306 {
307 parent_node = cur_node;
308 cur_node = cur_node->rc;
309 }
310 }
311
312 return (true == is_find)? parent_node : NULL;
313 }
314
315 // 查找某个结点为根节点的最结点
316
317 private:
318
319
320 //查找某个值
321 node *query_node(node *proot, int key)
322 {
323 if (NULL == proot)
324 {
325 return proot;
326 }
327
328 if (proot->data == key)
329 return proot;
330 else if (proot->data > key)
331 {
332 return query_node(proot->lc, key);
333 }
334 else if (proot->data < key)
335 {
336 return query_node(proot->rc, key);
337 }
338
339 return NULL;
340 }
341
342 // 后序遍历删除所有结点
343 void remove_all(node *proot)
344 {
345 if (NULL != proot)
346 {
347 remove_all(proot->lc);
348 remove_all(proot->rc);
349 delete proot;
350
351 dec_size();
352 }
353 }
354
355 // 先序遍历
356 void pre_order_traverse(node *proot)
357 {
358 if (NULL != proot)
359 {
360 cout << proot->data << ", ";
361 pre_order_traverse(proot->lc);
362 pre_order_traverse(proot->rc);
363 }
364 }
365
366 // 中序遍历
367 void in_order_traverse(node *proot)
368 {
369 if (NULL != proot)
370 {
371 in_order_traverse(proot->lc);
372 cout << proot->data << ", ";
373 in_order_traverse(proot->rc);
374 }
375 }
376
377 // 后续遍历
378 void post_order_traverse(node *proot)
379 {
380 if (NULL != proot)
381 {
382 post_order_traverse(proot->lc);
383 post_order_traverse(proot->rc);
384 cout << proot->data << ", ";
385 }
386 }
387
388 // 插入结点
389 node *insert(node *proot, int data)
390 {
391 // 结点不存在, 则创建
392 if (NULL == proot)
393 {
394 node *new_node = new(std::nothrow) node;
395 if (NULL != new_node)
396 {
397 new_node->data = data;
398 proot = new_node;
399
400 // 结点+1;
401 add_size();
402 }
403
404 return proot;
405 }
406
407 // 插入值比当前结点值还要小, 则应该插入到当前节点的左边
408 if (proot->data > data)
409 {
410 proot->lc = insert(proot->lc, data);
411 }
412 // 插入之比当前结点值还要打,则应该插入到当前结点的右边
413 else if (proot->data < data)
414 {
415 proot->rc = insert(proot->rc, data);
416 }
417
418 // 相等,则不插入结点。
419
420 return proot;
421 }
422
423 // size + 1
424 void add_size()
425 {
426 if (hmax_size_32767 == size)
427 return ;
428 size++;
429 }
430
431 // size - 1
432 void dec_size()
433 {
434 if ( hmin_size_0 == size)
435 {
436 return ;
437 }
438
439 size--;
440 }
441
442 private:
443 // 根结点
444 node *root;
445
446 // 当前树的结点个数
447 int size;
448 };
449
450
451
452 // 测试代码
453 int main()
454 {
455
456 bstree tree;
457
458 //
459 tree.insert_node(50);
460
461 tree.insert_node(30);
462 tree.insert_node(10);
463 tree.insert_node(0);
464 tree.insert_node(20);
465 tree.insert_node(40);
466
467 tree.insert_node(70);
468 tree.insert_node(90);
469 tree.insert_node(100);
470 tree.insert_node(60);
471 tree.insert_node(80);
472
473 // 前序遍历
474 cout << "前序遍历" << endl;
475 tree.pre_order();
476 cout << endl;
477
478 // 中序遍历
479 cout << "中序遍历" << endl;
480 tree.in_order();
481 cout << endl;
482
483 // 后序遍历
484 cout << "后序遍历" << endl;
485 tree.post_order();
486 cout << endl;
487
488 cout << "删除结点开始,结束请输入10086" << endl;
489
490 int del_key = 0;
491
492 while (true)
493 {
494 cout << "输入删除结点值 = ";
495 cin >> del_key;
496 if (10086 == del_key)
497 break;
498
499 tree.remove_node(del_key);
500
501 cout << "删除后,结点个数 = " << tree.get_size() << endl;
502 cout << "删除后, 中序遍历结果:" ;// << endl;
503 tree.in_order();
504 cout << endl << endl;
505 }
506
507 tree.remove_all();
508
509 return 0;
510 }

参考:《算法导论》

参考博文:https://www.cnblogs.com/fivestudy/p/10340647.html

!!版权声明:本文为博主原创文章,版权归原文作者和博客园共有,谢绝任何形式的 转载!!

作者:mohist

C++实现二叉搜索书(参考算法导论)的更多相关文章

  1. 算法dfs——二叉搜索树中最接近的值 II

    901. 二叉搜索树中最接近的值 II 中文 English 给定一棵非空二叉搜索树以及一个target值,找到 BST 中最接近给定值的 k 个数. 样例 样例 1: 输入: {1} 0.00000 ...

  2. 【转载】图解:二叉搜索树算法(BST)

    原文:图解:二叉搜索树算法(BST) 摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢!“岁月极美,在于它必然的流逝”“春花 秋月 夏日 冬雪”— ...

  3. 二叉搜索树算法详解与Java实现

    二叉查找树可以递归地定义如下,二叉查找树或者是空二叉树,或者是满足下列性质的二叉树: (1)若它的左子树不为空,则其左子树上任意结点的关键字的值都小于根结点关键字的值. (2)若它的右子树不为空,则其 ...

  4. [Swift]LeetCode450. 删除二叉搜索树中的节点 | Delete Node in a BST

    Given a root node reference of a BST and a key, delete the node with the given key in the BST. Retur ...

  5. 「面试高频」二叉搜索树&双指针&贪心 算法题指北

    本文将覆盖 「字符串处理」 + 「动态规划」 方面的面试算法题,文中我将给出: 面试中的题目 解题的思路 特定问题的技巧和注意事项 考察的知识点及其概念 详细的代码和解析 开始之前,我们先看下会有哪些 ...

  6. Java实现 LeetCode 450 删除二叉搜索树中的节点

    450. 删除二叉搜索树中的节点 给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变.返回二叉搜索树(有可能被更新)的根节点的引 ...

  7. LeetCode701 二叉搜索树中插入结点

    给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树. 返回插入后二叉搜索树的根节点. 保证原始二叉搜索树中不存在新值. 注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜 ...

  8. 刷题-力扣-230. 二叉搜索树中第K小的元素

    230. 二叉搜索树中第K小的元素 题目链接 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/kth-smallest-element-in-a ...

  9. [LeetCode] Delete Node in a BST 删除二叉搜索树中的节点

    Given a root node reference of a BST and a key, delete the node with the given key in the BST. Retur ...

随机推荐

  1. Atcoder Regular Contest 058 D - 文字列大好きいろはちゃん / Iroha Loves Strings(单调栈+Z 函数)

    洛谷题面传送门 & Atcoder 题面传送门 神仙题. mol 一发现场(bushi)独立切掉此题的 ycx %%%%%%% 首先咱们可以想到一个非常 naive 的 DP,\(dp_{i, ...

  2. JS 执行上下文的一次理解

    执行上下文 执行上下文概念 当代码运行时,会产生一个对应的执行环境,在这个环境中,变量会被事先提出来(变量提升),代码从上往下开始执行,就叫做执行上下文. 注:在定义变量是未直接赋值,使用默认值 un ...

  3. Docker-原理解析

    容器! Linux容器是与系统其他部分隔离开的一系列进程,从另一个镜像运行,并由该镜像提供支持进程所需的全部文件.容器提供的镜像包含了应用的所有依赖项,因而在从开发到测试再到生产的整个过程中,它都具有 ...

  4. JavaScript | 新手村(一)变量,运算和变量方法

    资料来自:JavaScript 第一步 1. 向 html 页面添加 JavaScript 1.1 内部 JavaScript 在 html 文件中的 </body> 标签前插入代码: & ...

  5. 34、在排序数组中查找元素的第一个和最后一个位置 | 算法(leetode,附思维导图 + 全部解法)300题

    零 标题:算法(leetode,附思维导图 + 全部解法)300题之(34)在排序数组中查找元素的第一个和最后一个位置 一 题目描述 二 解法总览(思维导图) 三 全部解法 1 方案1 1)代码: / ...

  6. 为什么重写equals必须重写hashCode

    目录 equals常见面试题 为什么要重写equals 重写equals不重写hashCode会存在什么问题 总结 equals常见面试题 在开始聊之前,我们先看几个常见的面试题,看看你能不能都回答上 ...

  7. 巩固javaweb的第二十七天

    巩固内容 正则表达式: 5. 指定字符串的开始和结尾 正则表达式中字符串的开始和结束符如表 2.6 所示. 表 2.6 开 始 和 结 尾 字符 作 用 ^ 指定以某个字符串开始 $ 指定以某个字符串 ...

  8. 日常Java 2021/10/26

    HashSet基于HashMap来实现的,是一个不允许有重复元素的集合.HashSet 允许有null 值. HashSet是无序的,即不会记录插入的顺序. HashSet不是线程安全的,如果多个线程 ...

  9. abide, able, abnormal

    abide 近/反义词:1. 忍受: bear, endure, put up with, stand, tolerate2. 遵守(abide by): accept, comply, confor ...

  10. 13个酷炫的JavaScript一行程序

    1. 获得一个随机的布尔值(true/false) const randomBoolean = () => Math.random() >= 0.5; console.log(random ...