二叉树c++实现
!!版权声明:本文为博主原创文章,版权归原文作者和博客园共有,谢绝任何形式的 转载!!
作者:mohist
--- 欢迎指正---
二叉树特点:
要么为空树;要么,当前结点的左孩子比当前结点值小,当前结点的右孩子比当前结点的值大。
1、插入:
1.1 插入结点的值比当前结点的值小,继续找当前结点的左子树,
1.2 插入结点的值比当前结点的值大,继续找当前结点的右子树,
1.3 找到合适的位置了,插入树。
2、删除:
2.1 删除结点是叶子结点,直接将其删除即可
2.2 删除结点只有左孩子或者只有右孩子,将其孩子结点删除,并将指向孩子结点的分支设置为空,c++是设置为NULL。不过更好的做法是,将孩子结点的值替换到当前结点,再删除孩子结点即可。
2.3 删除的结点同时含有左孩子与右孩子,需要找到删除结点的后继结点,将后继结点作为当前结点。
完整源码:
#include <iostream>
using namespace std; struct node
{
// 数据域
int data; // 左节点
node *lc; // 右结点
node *rc; // 构造函数
node()
: data(0)
, lc(NULL)
, rc(NULL)
{
}
}; // bst
class bstree
{
public:
enum
{
hmax_size_32767 = 32767,
hmin_size_0 = 0,
}; public: // 构造函数
bstree()
: root(NULL)
, size(0)
{
} // 析构函数
virtual ~bstree(){} int get_size()
{
return size;
} // 插入结点
void insert_node(int data)
{
int cur_size = get_size();
if (hmax_size_32767 == cur_size)
{
cout << "insert node error, the size of the tree is max" << endl;
return ;
}
root = insert(root, data);
} // 先序遍历(前序遍历)
void pre_order()
{
pre_order_traverse(root);
} // 中序遍历
void in_order()
{
in_order_traverse(root);
} // 后序遍历
void post_order()
{
post_order_traverse(root);
} /*
查找某个结点
int key - 查找结果 返回值:
NULL : 可能为root为空 或者 没有找到
!= NULL, 找到结点
*/
node* query(int key)
{
if (NULL == root)
{
cout << "query error, root = null" << endl;
return NULL;
} return query_node(root, key);
} // 删除树
void remove_all()
{
if (NULL == root)
{
cout << "remove all failed, root = null" << endl;
return;
} remove_all(root); int cur_size = get_size();
if (0 == cur_size)
root = NULL;
} // 删除某个结点
void remove_node(int del_data)
{
if (NULL == root)
{
cout << "remove node error, root = null" << endl;
return;
} node *parent_node = NULL;
node *del_node = root; // 找到删除结点的父节点与删除结点
while (del_node)
{
if (del_data == del_node->data)
break;
else if (del_data > del_node->data)
{
parent_node = del_node;
del_node = del_node->rc;
}
else if (del_data < del_node->data)
{
parent_node = del_node;
del_node = del_node->lc;
}
} // 若没有找到要删除的结点
if (NULL == del_node)
{
cout << "remove node error, " << del_data << " was not find" << endl;
return;
} // 1、若删除的结点没有左子树和右子树
if ( (NULL == del_node->lc) && (NULL == del_node->rc) )
{
// 为什么要先判断根结点,因为根结点的父节点找不到,结果为NULL,
// 1.1 可能只有一个根结点, 将root释放值为空
if (del_node == root)
{
root = NULL;
delete del_node;
del_node = NULL; dec_size();
return;
} // 1.2 非根结点,那就是叶子结点了, 将父节点指向删除结点的分支指向NULL
if (del_node == parent_node->lc)
parent_node->lc = NULL;
else if (del_node == parent_node->rc)
parent_node->rc = NULL; // 释放结点
delete del_node;
del_node = NULL;
dec_size();
} // 2、若删除结点只有左孩子,没有右孩子
else if ( (NULL != del_node->lc) && (NULL == del_node->rc) )
{
// 2.1 删除结点为根结点,则将删除结点的左孩子替代当前删除结点
if (del_node == root)
{
root = root->lc;
}
// 2.2 其他结点,将删除结点的左孩子作为父节点的左孩子
else
{
if (parent_node->lc == del_node)
parent_node->lc = del_node->lc;
else if (parent_node->rc == del_node)
parent_node->rc = del_node->lc;
} delete del_node;
del_node = NULL; dec_size();
} // 3、若删除结点只有右孩子
else if ( (NULL == del_node->lc) && (NULL != del_node->rc) )
{
// 3.1 若为根结点
if (root == del_node)
{
root = root->rc;
}
else
{
if (del_node == parent_node->lc)
parent_node->lc = del_node->rc;
else if (del_node == parent_node->rc)
parent_node->rc = del_node->rc;
} delete del_node;
del_node = NULL; dec_size();
} // 4、若删除结点既有左孩子,又有右孩子,需要找到删除结点的后继结点作为根结点
else if ( (NULL != del_node->lc) && (NULL != del_node->rc) )
{
node *successor_node = del_node->rc;
parent_node = del_node; while (successor_node->lc)
{
parent_node = successor_node;
successor_node = successor_node->lc;
} // 交换后继结点与当前删除结点的数据域
del_node->data = successor_node->data;
// 将指向后继结点的父节点的孩子设置后继结点的右子树
if (successor_node == parent_node->lc)
parent_node->lc = successor_node->rc;
else if (successor_node == parent_node->rc)
parent_node->rc = successor_node->rc; // 删除后继结点
del_node = successor_node;
delete del_node;
del_node = NULL; dec_size();
}
} // 返回以proot为根结点的最小结点
node *get_min_node(node *proot)
{
if (NULL == proot->lc)
return proot; return get_min_node(proot->lc);
} // 返回以proo为根节点的最大结点
node *get_max_node(node *proot)
{
if (NULL == proot->rc)
return proot; return get_max_node(proot->rc);
} // 返回根节点
node *get_root_node()
{
return root;
} // 返回proot结点的父节点
node *get_parent_node(int key)
{
// 当前结点
node *cur_node = NULL;
// 父节点
node *parent_node = NULL; cur_node = root; // 标记是否找到
bool is_find = false;
while (cur_node)
{
if (key == cur_node->data)
{
is_find = true;
break;
} // 因为比当前结点的值还要小,所以需要查找当前结点的左子树
else if (key < cur_node->data)
{
parent_node = cur_node;
cur_node = cur_node->lc;
}
// 同上, 查找当前结点的右子树
else if (key > cur_node->data)
{
parent_node = cur_node;
cur_node = cur_node->rc;
}
} return (true == is_find)? parent_node : NULL;
} private: //查找某个值
node *query_node(node *proot, int key)
{
if (NULL == proot)
{
return proot;
} if (proot->data == key)
return proot;
else if (proot->data > key)
{
return query_node(proot->lc, key);
}
else if (proot->data < key)
{
return query_node(proot->rc, key);
} return NULL;
} // 后序遍历删除所有结点
void remove_all(node *proot)
{
if (NULL != proot)
{
remove_all(proot->lc);
remove_all(proot->rc);
delete proot; dec_size();
}
} // 先序遍历
void pre_order_traverse(node *proot)
{
if (NULL != proot)
{
cout << proot->data << ", ";
pre_order_traverse(proot->lc);
pre_order_traverse(proot->rc);
}
} // 中序遍历
void in_order_traverse(node *proot)
{
if (NULL != proot)
{
in_order_traverse(proot->lc);
cout << proot->data << ", ";
in_order_traverse(proot->rc);
}
} // 后续遍历
void post_order_traverse(node *proot)
{
if (NULL != proot)
{
post_order_traverse(proot->lc);
post_order_traverse(proot->rc);
cout << proot->data << ", ";
}
} // 插入结点
node *insert(node *proot, int data)
{
// 结点不存在, 则创建
if (NULL == proot)
{
node *new_node = new(std::nothrow) node;
if (NULL != new_node)
{
new_node->data = data;
proot = new_node; // 结点+1;
add_size();
} return proot;
} // 插入值比当前结点值还要小, 则应该插入到当前节点的左边
if (proot->data > data)
{
proot->lc = insert(proot->lc, data);
}
// 插入之比当前结点值还要打,则应该插入到当前结点的右边
else if (proot->data < data)
{
proot->rc = insert(proot->rc, data);
} // 相等,则不插入结点。 return proot;
} // size + 1
void add_size()
{
if (hmax_size_32767 == size)
return ;
size++;
} // size - 1
void dec_size()
{
if ( hmin_size_0 == size)
{
return ;
} size--;
} private:
// 根结点
node *root; // 当前树的结点个数
int size;
}; // 测试代码
int main()
{ bstree tree; //
tree.insert_node(50); tree.insert_node(30);
tree.insert_node(10);
tree.insert_node(0);
tree.insert_node(20);
tree.insert_node(40); tree.insert_node(70);
tree.insert_node(90);
tree.insert_node(100);
tree.insert_node(60);
tree.insert_node(80); // 前序遍历
cout << "前序遍历" << endl;
tree.pre_order();
cout << endl; // 中序遍历
cout << "中序遍历" << endl;
tree.in_order();
cout << endl; // 后序遍历
cout << "后序遍历" << endl;
tree.post_order();
cout << endl; cout << "删除结点开始,结束请输入10086" << endl; int del_key = 0; while (true)
{
cout << "输入删除结点值 = ";
cin >> del_key;
if (10086 == del_key)
break; tree.remove_node(del_key); cout << "删除后,结点个数 = " << tree.get_size() << endl;
cout << "删除后, 中序遍历结果:" ;// << endl;
tree.in_order();
cout << endl << endl;
} tree.remove_all(); return 0;
}
测试结果:

二叉树c++实现的更多相关文章
- [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法
二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...
- 二叉树的递归实现(java)
这里演示的二叉树为3层. 递归实现,先构造出一个root节点,先判断左子节点是否为空,为空则构造左子节点,否则进入下一步判断右子节点是否为空,为空则构造右子节点. 利用层数控制迭代次数. 依次递归第二 ...
- c 二叉树的使用
简单的通过一个寻找嫌疑人的小程序 来演示二叉树的使用 #include <stdio.h> #include <stdlib.h> #include <string.h& ...
- Java 二叉树遍历右视图-LeetCode199
题目如下: 题目给出的例子不太好,容易让人误解成不断顺着右节点访问就好了,但是题目意思并不是这样. 换成通俗的意思:按层遍历二叉树,输出每层的最右端结点. 这就明白时一道二叉树层序遍历的问题,用一个队 ...
- 数据结构:二叉树 基于list实现(python版)
基于python的list实现二叉树 #!/usr/bin/env python # -*- coding:utf-8 -*- class BinTreeValueError(ValueError): ...
- [LeetCode] Path Sum III 二叉树的路径和之三
You are given a binary tree in which each node contains an integer value. Find the number of paths t ...
- [LeetCode] Find Leaves of Binary Tree 找二叉树的叶节点
Given a binary tree, find all leaves and then remove those leaves. Then repeat the previous steps un ...
- [LeetCode] Verify Preorder Serialization of a Binary Tree 验证二叉树的先序序列化
One way to serialize a binary tree is to use pre-oder traversal. When we encounter a non-null node, ...
- [LeetCode] Binary Tree Vertical Order Traversal 二叉树的竖直遍历
Given a binary tree, return the vertical order traversal of its nodes' values. (ie, from top to bott ...
- [LeetCode] Binary Tree Longest Consecutive Sequence 二叉树最长连续序列
Given a binary tree, find the length of the longest consecutive sequence path. The path refers to an ...
随机推荐
- 端口TCP——简介
cmd命令:telnet 如果需要搭建外网可访问的网站,可以顺便勾选HTTP,HTTPS端口:
- Linux-设置终端界面的字体颜色和自定义常用快捷功能
.bashrc是一个隐藏的文件,要打开并修改该文件需要: (0)命令:cd ~ (1)命令:ls -a 找到文件 .bashrc: (2) 命令 vim ~/.bashrc 进入到文件: (3) 直接 ...
- nginx 的一个conf配置
server { listen 80 default_server; server_name www.caipudq.cn caipudq.cn *.caipudq.cn; root /mnt/www ...
- 《Redis设计与实现》知识点目录
Redis设计与实现 第一部分 数据结构与对象 第二章 简单动态字符串 p8 简单动态字符串SDS 2.1 SDS的定义 p9 每个sds.h/sdshdr结构表示一个SDS值 2.2 SDS与C字符 ...
- 使用input+datalist简单实现实时匹配的可编辑下拉列表-并解决选定后浏览器默认只显示value的可读性问题
问题背景 最近小伙伴提了一个希望提高后台下拉列表可操作性的需求,原因是下拉列表选项过多,每次下拉选择比较费时费力且容易出错,硬着头皮啃了啃前端知识,网上搜寻了一些下拉列表实现的资料,这里总结一下. P ...
- .NET Core基础篇之:集成Swagger文档与自定义Swagger UI
Swagger大家都不陌生,Swagger (OpenAPI) 是一个与编程语言无关的接口规范,用于描述项目中的 REST API.它的出现主要是节约了开发人员编写接口文档的时间,可以根据项目中的注释 ...
- 浅讲.Net 6 之 WebApplicationBuilder
介绍 .Net 6为我们带来的一种全新的引导程序启动的方式.与之前的拆分成Program.cs和Startup不同,整个引导启动代码都在Program.cs中. WebApplicationBuild ...
- 《C陷阱与缺陷》 第0章导读 第1章词法陷阱
1.= 与==的区别 赋值运算符= 的优先级要小于逻辑运算符== 也就是说,会进行先逻辑上的比较,然后再把比较结果进行赋值,很合理. getc库是什么??? 1.C语言中有单字符 = 也有多字符单元如 ...
- 【编程思想】【设计模式】【其他模式】graph_search
Python版 https://github.com/faif/python-patterns/blob/master/other/graph_search.py #!/usr/bin/env pyt ...
- redis 之 哨兵
#:编译安装redis4.0 [root@master ~]# tar xf redis-4.0.14.tar.gz [root@master ~]# cd redis-4.0.14/ [root@m ...