[C++]二叉链-二叉树存储
二叉链存二叉树
预备知识
感谢:
代码参考:CSDN博主「云雨澄枫」的原创文章
代码解析
结构体 BiNode
template<class T>
struct BiNode{
T data;
BiNode<T> *lchild,*rchild;
};
Node 结点
这个结构体就是用来存储二叉链的每一个节点的
- data
表示这个节点所存的值
- *lchild & *rchild
表示指向 左子树 和 右子树 的指针
这样的结构能很好地存下二叉树:

(具体的建树方法会放在后面解释)
类 BiTree
template <class T>
class BiTree{
public:
//构造 & 折构
BiTree(){root = Creat(root);}
~BiTree(){Release(root);}
//遍历
void PreOrder(){PreOrder(root);}
void InOrder(){InOrder(root);}
void PostOrder(){PostOrder(root);}
void LeverOrder();
//树的深度
int Depth(){Depth(root);}
//叶子结点数量
void CaculateLeafNum(){CaculateLeafNum(root);}
//交换左右子树
void swap(){swap(root);}
private:
BiNode<T> *root;//<-根节点在这里
BiNode<T> *Creat(BiNode<T> *bt);
void Release(BiNode<T> *bt);
void PreOrder(BiNode<T> *bt);
void InOrder(BiNode<T> *bt);
void PostOrder(BiNode<T> *bt);
int Depth(BiNode<T> *root);
void CaculateLeafNum(BiNode<T>* root);
void swap(BiNode<T> *root);
};
这便是树的主体
一个 BiTree 的类就代表一颗二叉树
- public
在这里定义了一些之后会用到的函数以及构造函数和折构函数
这里知道有这些东西即可
- private
这里则有一些 public 会用到的函数
以及这个树的根节点
构造函数 & 折构函数
- 构造函数
在类中 是这样写的:
BiTree(){root = Creat(root);}
构造这个树是通过 Creat 这个函数来实现的
Creat_Code:
template <class T>
BiNode<T> *BiTree<T>::Creat(BiNode<T> *bt)
{
T t;
cin >> t;
if(t == '#')
bt = NULL;
else {
bt = new BiNode<T>;
bt->data = t;
bt->lchild = Creat(bt->lchild);
bt->rchild = Creat(bt->rchild);
}
return bt;
}
在讲构造函数之前
还需要提一嘴其输入方式
这里是采用前序遍历的方式进行输入
同时还需要以 "#" 输入叶子结点的空子结点
例子:
cin:
ABD#G###CE##F##

- 图中的序号即代表 cin 中的第几个字符
知道了输入的顺序之后
代码就变得好理解很多了
创建一个结点的时候
首先输入这个结点的值(就是 t)
若其值是 "#" 那就不继续往下面创造新结点了
直接让 bt 为 空指针
并把这个指针返回
若其值不为 "#"
那说明后面可能还有结点需要添加
就继续在左右子结点上调用 Creat函数
bt = new BiNode<T>;
这行代码可能还需要解释一下
new 是用来开辟新的内存空间的关键字
这里相当于开辟了一个新的结点结构体
而 bt 存下了这个结点结构体的指针
- 折构函数
~BiTree(){Release(root);}
折构函数和构造函数一样是用类名来作为函数名的
不过需要在前面加一个 "~"
这个函数调用了 Release 这个函数
template<class T>
void BiTree<T>::Release(BiNode<T> *bt){
if(bt != NULL){
Release(bt->lchild);
Release(bt->rchild);
delete bt;
}
}
delete 用于删除内存的关键词
这个函数因该很好理解
就是从上往下搜
从下往上删
就不过多解释了
遍历函数
这个分两部分将
第一部分 : 前/中/后序遍历
这些代码原理相同 就随便挑一个讲好了
template <class T>
void BiTree<T>::PreOrder(BiNode<T> *bt){
if (bt == NULL)
return;
else {
cout << bt->data;
PreOrder(bt->lchild);
PreOrder(bt->rchild);
}
}
从 root结点 开始搜索
如果不是空结点 那就直接输出
然后往两边找
决定前中后的只在于
输出与往两侧搜索语句的顺序
第二部分 : 层序遍历
还是用这个图

Code:
template<class T>
void BiTree<T>::LeverOrder(){
int front = -1,rear = -1;
BiNode<T> *Q[100];
if(root == NULL) return;
Q[++rear] = root;
while(front != rear){
BiNode<T> *q = Q[++front];
cout << q->data;
if(q->lchild != NULL) Q[++rear] = q->lchild;
if(q->rchild != NULL) Q[++rear] = q->rchild;
}
}
这里是用一个数组和两个变量来实现了队列的功能
接下来我们来模拟一下

这样就可以实现层序遍历了
求树的深度
Code:
template<class T>
int BiTree<T>::Depth(BiNode<T> *root){
int hl,hr;
if(root == NULL)
return 0;
else{
hl = Depth(root->lchild);
hr = Depth(root->rchild);
return max(hl,hr) + 1;
}
}
深度要找的是最深的叶子结点的层数
因此直接左右找取最大值即可
求叶子结点数量
Code:
template<class T>
void BiTree<T>::CaculateLeafNum(BiNode<T> *root){
if(!root) return;
if(root->lchild == NULL && root->rchild == NULL) Leaf_Count++;
CaculateLeafNum(root->lchild);
CaculateLeafNum(root->rchild);
}
首先我们要知道叶子结点的特征:
没有儿子节点
(就是所有儿子节点都为 NULL)
所以左右搜找到无儿子 +1 即可
交换左右子树
template<class T>
void BiTree<T>::swap(BiNode<T> *root){
BiNode<T> *temp;
if(root == NULL)
return;
else{
temp = root->lchild;
root->lchild = root->rchild;
root->rchild = temp;
swap(root->lchild);
swap(root->rchild);
}
}
由于二叉链的本质就是指针的堆叠
因此直接交换指针的存值就可以了
Code
#include<bits/stdc++.h>
using namespace std;
template<class T>
struct BiNode{
T data;
BiNode<T> *lchild,*rchild;
};
template <class T>
class BiTree{
public:
//构造 & 折构
BiTree(){root = Creat(root);}
~BiTree(){Release(root);}
//遍历
void PreOrder(){PreOrder(root);}
void InOrder(){InOrder(root);}
void PostOrder(){PostOrder(root);}
void LeverOrder();
//树的深度
int Depth(){Depth(root);}
//叶子结点数量
void CaculateLeafNum(){CaculateLeafNum(root);}
//交换左右子树
void swap(){swap(root);}
private:
BiNode<T> *root;
BiNode<T> *Creat(BiNode<T> *bt);
void Release(BiNode<T> *bt);
void PreOrder(BiNode<T> *bt);
void InOrder(BiNode<T> *bt);
void PostOrder(BiNode<T> *bt);
int Depth(BiNode<T> *root);
void CaculateLeafNum(BiNode<T>* root);
void swap(BiNode<T> *root);
};
int Leaf_Count = 0;
template <class T>
BiNode<T> *BiTree<T>::Creat(BiNode<T> *bt)
{
T t;
cin >> t;
if(t == '#')
bt = NULL;
else {
bt = new BiNode<T>;
bt->data = t;
bt->lchild = Creat(bt->lchild);
bt->rchild = Creat(bt->rchild);
}
return bt;
}
template<class T>
void BiTree<T>::Release(BiNode<T> *bt){
if(bt != NULL){
Release(bt->lchild);
Release(bt->rchild);
delete bt;
}
}
template <class T>
void BiTree<T>::PreOrder(BiNode<T> *bt){
if(bt == NULL)
return;
else {
cout << bt->data;
PreOrder(bt->lchild);
PreOrder(bt->rchild);
}
}
template<class T>
void BiTree<T>::InOrder(BiNode<T> *bt){
if(bt == NULL)
return;
else{
InOrder(bt->lchild);
cout << bt->data;
InOrder(bt->rchild);
}
}
template<class T>
void BiTree<T>::PostOrder(BiNode<T> *bt){
if(bt == NULL)
return;
else{
PostOrder(bt->lchild);
PostOrder(bt->rchild);
cout << bt->data;
}
}
template<class T>
void BiTree<T>::LeverOrder(){
int front = -1,rear = -1;
BiNode<T> *Q[100];
if(root == NULL) return;
Q[++rear] = root;
while(front != rear){
BiNode<T> *q = Q[++front];
cout << q->data;
if(q->lchild != NULL) Q[++rear] = q->lchild;
if(q->rchild != NULL) Q[++rear] = q->rchild;
}
}
template<class T>
int BiTree<T>::Depth(BiNode<T> *root){
int hl,hr;
if(root == NULL)
return 0;
else{
hl = Depth(root->lchild);
hr = Depth(root->rchild);
return max(hl,hr) + 1;
}
}
template<class T>
void BiTree<T>::CaculateLeafNum(BiNode<T> *root){
if(!root) return;
if(root->lchild == NULL && root->rchild == NULL) Leaf_Count++;
CaculateLeafNum(root->lchild);
CaculateLeafNum(root->rchild);
}
template<class T>
void BiTree<T>::swap(BiNode<T> *root){
BiNode<T> *temp;
if(root == NULL)
return;
else{
temp = root->lchild;
root->lchild = root->rchild;
root->rchild = temp;
swap(root->lchild);
swap(root->rchild);
}
}
int main(){
BiTree<char>* bitree=new BiTree<char>;
cout<<"前序遍历";
bitree->PreOrder();
cout << endl;
cout<<"中序遍历";
bitree->InOrder();
cout << endl;
cout<<"后序遍历";
bitree->PostOrder();
cout << endl;
cout<<"层序遍历";
bitree->LeverOrder();
cout << endl;
cout<<"深度:"<<bitree->Depth()<<endl;
bitree->CaculateLeafNum();
cout<<"叶子结点个数:"<<Leaf_Count<<endl;
bitree->swap();
cout<<"左右子树交换后的层序:";
bitree->LeverOrder();
return 0;
}
[C++]二叉链-二叉树存储的更多相关文章
- 二叉搜索树 & 二叉树 & 遍历方法
二叉搜索树 & 二叉树 & 遍历方法 二叉搜索树 BST / binary search tree https://en.wikipedia.org/wiki/Binary_searc ...
- HDU3791二叉搜索树(二叉树)
Problem Description 判断两序列是否为同一二叉搜索树序列 Input 开始一个数n,(1<=n<=20) 表示有n个需要判断,n= 0 的时候输入结束.接下去一行是一 ...
- 二叉苹果树 - 二叉树树型DP
传送门 中文题面: 题目描述 有一棵苹果树,如果树枝有分叉,一定是分 2 叉(就是说没有只有 1 个儿子的结点,这棵树共有N 个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一 ...
- 数据结构图文解析之:二叉堆详解及C++模板实现
0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...
- 数据结构-二叉搜索树的js实现
一.树的相关概念 1.基本概念 子树 一个子树由一个节点和它的后代构成. 节点的度 节点所拥有的子树的个数. 树的度 树中各节点度的最大值 节点的深度 节点的深度等于祖先节点的数量 树的高度 树的高度 ...
- 二叉堆 及 大根堆的python实现
Python 二叉堆(binary heap) 二叉堆是一种特殊的堆,二叉堆是完全二叉树或者是近似完全二叉树.二叉堆满足堆特性:父节点的键值总是保持固定的序关系于任何一个子节点的键值,且每个节点的左子 ...
- javascript实现二叉搜索树
在使用javascript实现基本的数据结构中,练习了好几周,对基本的数据结构如 栈.队列.链表.集合.哈希表.树.图等内容进行了总结并且写了笔记和代码. 在 github中可以看到 点击查看,可以 ...
- 二叉树的二叉链表存储结构及C++实现
前言:存储二叉树的关键是如何表示结点之间的逻辑关系,也就是双亲和孩子之间的关系.在具体应用中,可能要求从任一结点能直接访问到它的孩子. 一.二叉链表 二叉树一般多采用二叉链表(binary linke ...
- [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法
二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...
- C#实现二叉树--二叉链表结构
二叉树的简单介绍 关于二叉树的介绍请看这里 : 二叉树的简单介绍 http://www.cnblogs.com/JiYF/p/7048785.html 二叉链表存储结构: 二叉树的链式存储结构是指,用 ...
随机推荐
- docker 公有仓库与私有仓库常见操作
本文为博主原创,转载请注明出处: 自建一个Docker仓库,可以使用Docker官方提供的开源项目Docker Registry.以下是一些基本步骤: 安装Docker Registry: 在服务器上 ...
- C语言基础--数组详细说明
目录 一.什么是数组 二.一维数组 1.一维数组创建 2.一维数组的使用 2.1 索引值 2.2 遍历数组 2.3 如何使用sizeof()计算出数组的长度 三.二维数组 1.二维数组的创建 2.二维 ...
- zabbix 可计算监控项使用 last() 与 avg() 的区别
使用zabbix的可计算监控项时遇到的问题 在agent异常退出的情况下,使用last()的监控项依然在产出数据! 分析解决 last()函数会跳过空值,取最后一个有效值计算.遍查文档,只有用avg( ...
- Windows 下搭建 Appium + Android+python 自动化测试环境
前言 本来并不打算写这么一篇文章,但是实践下来发现网上的各种教程里大致有两个问题.一是文章有些跟不上时代,目前android开发和测试的技术更新都比较快,内容有些过期.二是细节部分不是太完整,拼拼凑凑 ...
- 最全linux基础知识
linux基础知识 [root@localhost ~]# 各位置表示什么意识 root:表示用户名 (现在的用户是root切换为test便是张三) localhost:表示主机名 (当前主机名切换为 ...
- redux的三个概念与三大核心
1.什么是redux?一个组件里可能会有很多的状态,比如控制某个内容显示的flag,从后端获取的展示数据,那么这些状态可以在自己的单个页面进行管理,也可以选择别的管理方式,redux就是是一种状态管理 ...
- 2023NepCTF-RE部分题解
2023NepCTF-RE部分题解 九龙拉棺 过反调试 很容易发现 void __stdcall sub_401700() 里面有tea的痕迹 接出来发现只是前半部分 #include <std ...
- 5、Spring之bean的作用域和生命周期
5.1.bean的作用域 5.1.1.单例(默认且常用) 5.1.1.1.配置bean 注意:当bean不配置scope属性时,默认是singleton(单例) <?xml version=&q ...
- 震惊!CSS 也能实现碰撞检测?
本文,我们将一起学习,使用纯 CSS,实现如下所示的动画效果: 上面的动画效果,非常有意思,核心有两点: 小球随机做 X.Y 方向的直线运动,并且能够实现碰撞到边界的时候,实现反弹效果 小球在碰撞边界 ...
- 浅析三维模型OBJ格式轻量化处理常见问题与处理措施
浅析三维模型OBJ格式轻量化处理常见问题与处理措施 在三维模型OBJ格式轻量化处理过程中,可能会遇到一些问题.以下是一些常见问题以及相应的解决方法: 1.文件大小过大: OBJ格式的三维模型文件通常包 ...