C++实现二叉搜索书(参考算法导论)
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++实现二叉搜索书(参考算法导论)的更多相关文章
- 算法dfs——二叉搜索树中最接近的值 II
901. 二叉搜索树中最接近的值 II 中文 English 给定一棵非空二叉搜索树以及一个target值,找到 BST 中最接近给定值的 k 个数. 样例 样例 1: 输入: {1} 0.00000 ...
- 【转载】图解:二叉搜索树算法(BST)
原文:图解:二叉搜索树算法(BST) 摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢!“岁月极美,在于它必然的流逝”“春花 秋月 夏日 冬雪”— ...
- 二叉搜索树算法详解与Java实现
二叉查找树可以递归地定义如下,二叉查找树或者是空二叉树,或者是满足下列性质的二叉树: (1)若它的左子树不为空,则其左子树上任意结点的关键字的值都小于根结点关键字的值. (2)若它的右子树不为空,则其 ...
- [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 ...
- 「面试高频」二叉搜索树&双指针&贪心 算法题指北
本文将覆盖 「字符串处理」 + 「动态规划」 方面的面试算法题,文中我将给出: 面试中的题目 解题的思路 特定问题的技巧和注意事项 考察的知识点及其概念 详细的代码和解析 开始之前,我们先看下会有哪些 ...
- Java实现 LeetCode 450 删除二叉搜索树中的节点
450. 删除二叉搜索树中的节点 给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变.返回二叉搜索树(有可能被更新)的根节点的引 ...
- LeetCode701 二叉搜索树中插入结点
给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树. 返回插入后二叉搜索树的根节点. 保证原始二叉搜索树中不存在新值. 注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜 ...
- 刷题-力扣-230. 二叉搜索树中第K小的元素
230. 二叉搜索树中第K小的元素 题目链接 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/kth-smallest-element-in-a ...
- [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 ...
随机推荐
- CURL常用参数
1. CURL简介 cURL是一个利用URL语法在命令行下工作的文件传输工具.它支持文件上传和下载,是综合传输工具.cURL就是客户端(client)的URL工具的意思. 2. 常用参数 -k:不校验 ...
- msyql_union
MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中.多个 SELECT 语句会删除重复的数据. 语法 MySQL UNION 操作符语法格式: SELECT ...
- linux下vi与vim区别以及vim的使用-------vim编辑时脚本高光显示语法
vi与vimvi编辑器是所有Unix及Linux系统下标准的编辑器,他就相当于windows系统中的记事本一样,它的强大不逊色于任何最新的文本编辑器.他是我们使用Linux系统不能缺少的工具.由于对U ...
- A Child's History of England.33
To strengthen his power, the King with great ceremony betrothed his eldest daughter Matilda, then a ...
- day16 Linux三剑客之awk
day16 Linux三剑客之awk 1.什么是awk,主要作用是什么? 什么是awk,主要作用是什么? awk 主要用来处理文件,将文本按照指定的格式输出.其中包含变量,循环以及数组. 2.awk的 ...
- Shell学习(三)——Shell条件控制和循环语句
参考博客: [1]Shell脚本的条件控制和循环语句 一.条件控制语句 1.if语句 1.1语法格式: if [ expression ] then Statement(s) to be execut ...
- JavaIO——System对IO的支持、序列化
1.系统类对IO的支持 在我们学习PriteWriter.PrintStream里面的方法print.println的时候是否观察到其与我们之前一直使用的系统输出很相似呢?其实我们使用的系统输出就是采 ...
- ORACLE dba_extents
dba_extents OWNER 拥有者 SEGMENT_NAME 段名 PARTITION_NAME 分区名 SEGMENT_TYPE 段类型 TABLESPACE_NAME 表空间名 EXTEN ...
- Output of C++ Program | Set 10
Predict the output of following C++ programs. Question 1 1 #include<iostream> 2 #include<st ...
- IOS_UIButton去掉系统的按下高亮置灰效果
setAdjustsImageWhenHighlighted // default is YES. if YES, image is drawn darker when highlighted(p ...