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. CURL常用参数

    1. CURL简介 cURL是一个利用URL语法在命令行下工作的文件传输工具.它支持文件上传和下载,是综合传输工具.cURL就是客户端(client)的URL工具的意思. 2. 常用参数 -k:不校验 ...

  2. msyql_union

    MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中.多个 SELECT 语句会删除重复的数据. 语法 MySQL UNION 操作符语法格式: SELECT ...

  3. linux下vi与vim区别以及vim的使用-------vim编辑时脚本高光显示语法

    vi与vimvi编辑器是所有Unix及Linux系统下标准的编辑器,他就相当于windows系统中的记事本一样,它的强大不逊色于任何最新的文本编辑器.他是我们使用Linux系统不能缺少的工具.由于对U ...

  4. A Child's History of England.33

    To strengthen his power, the King with great ceremony betrothed his eldest daughter Matilda, then a ...

  5. day16 Linux三剑客之awk

    day16 Linux三剑客之awk 1.什么是awk,主要作用是什么? 什么是awk,主要作用是什么? awk 主要用来处理文件,将文本按照指定的格式输出.其中包含变量,循环以及数组. 2.awk的 ...

  6. Shell学习(三)——Shell条件控制和循环语句

    参考博客: [1]Shell脚本的条件控制和循环语句 一.条件控制语句 1.if语句 1.1语法格式: if [ expression ] then Statement(s) to be execut ...

  7. JavaIO——System对IO的支持、序列化

    1.系统类对IO的支持 在我们学习PriteWriter.PrintStream里面的方法print.println的时候是否观察到其与我们之前一直使用的系统输出很相似呢?其实我们使用的系统输出就是采 ...

  8. ORACLE dba_extents

    dba_extents OWNER 拥有者 SEGMENT_NAME 段名 PARTITION_NAME 分区名 SEGMENT_TYPE 段类型 TABLESPACE_NAME 表空间名 EXTEN ...

  9. Output of C++ Program | Set 10

    Predict the output of following C++ programs. Question 1 1 #include<iostream> 2 #include<st ...

  10. IOS_UIButton去掉系统的按下高亮置灰效果

    setAdjustsImageWhenHighlighted   // default is YES. if YES, image is drawn darker when highlighted(p ...