二叉树的建立方法总结
之前已经介绍了二叉树的四种遍历(如果不熟悉请戳我),下面介绍一些二叉树的建立方式。首先需要明确的是,由于二叉树的定义是递归的,所以用递归的思想建立二叉树是很自然的想法。
1. 交互式问答方式
这种方式是最直接的方式,就是先询问用户根节点是谁,然后每次都询问用户某个节点的左孩子是谁,右孩子是谁。代码如下(其中字符'#'代表空节点):
#include <cstdio>
#include <cstdlib>
using namespace std;
typedef struct BTNode *Position;
typedef Position BTree;
struct BTNode
{
char data;
Position lChild, rChild;
};
BTree CreateBTree(BTree bt, bool isRoot)
{
char ch;
if (isRoot)
printf("Root: ");
fflush(stdin); /* 清空缓存区 */
scanf("%c", &ch);
fflush(stdin);
if (ch != '#')
{
isRoot = false;
bt = new BTNode;
bt->data = ch;
bt->lChild = NULL;
bt->rChild = NULL;
printf("%c's left child is: ", bt->data);
bt->lChild = CreateBTree(bt->lChild, isRoot);
printf("%c's right child is: ", bt->data);
bt->rChild = CreateBTree(bt->rChild, isRoot);
}
return bt;
}
int main()
{
BTree bt;
bt = CreateBTree(bt, true);
LevelOrderTraversal(bt); /* 层序遍历 */
return 0;
}
2. 根据先序序列
例如输入序列ABDH##I##E##CF#J##G##(#表示空),则会建立如下图所示的二叉树
思路和第一种方式很相似,只是代码实现细节有一点区别,这里给出创建函数
BTree CreateBTree()
{
BTree bt = NULL;
char ch;
scanf("%c", &ch);
if (ch != '#')
{
bt = new BTNode;
bt->data = ch;
bt->lChild = CreateBTree();
bt->rChild = CreateBTree();
}
return bt;
}
3. 根据中序序列和后序序列
和方式二不同的是,这里的序列不会给出空节点的表示,所以如果只给出先序序列,中序序列,后序序列中的一种,不能唯一确定一棵二叉树。但是如果给出中序序列和后序序列或者先序序列和中序序列就可以唯一确定一棵树。根据三种遍历方式的特点,我们可以利用先序序列或后序序列确定根节点,可以利用中序序列确定左右孩子。
由后序序列“左子树->右子树->根节点”性质可知后序序列的最后一个一定为这棵树的根节点,而又根据中序序列“左子树->根节点->右子树”的性质,由后序序列得到的根节点可以将中序序列分为左子树中序序列和右子树中序序列。然后根据序列的个数相同,可以将后序序列分为左子树后序序列和右子树后序序列。依次递归的进行,直到序列长度为空递归返回。同理,根据先序序列的“根节点->左子树->右子树”性质可得先序序列的第一个一定为这棵树的根节点,之后与上述类似。
例如:一棵二叉树的中序序列为:ABCEFGHD,后序序列为: ABFHGEDC。建立的二叉树如下图:
代码如下:
/*
通过中序序列和后序序列建树,然后先序遍历输出
输入(第一行为中序,第二行为后序):
ABCEFGHD
ABFHGEDC
输出:
CBADEGFH
*/
#include <cstdio>
#include <cstdlib>
using namespace std;
const int N = 1010;
typedef struct BTNode *Position;
typedef Position BTree;
struct BTNode
{
char data;
Position lChild, rChild;
};
BTree CreateBTree(char inOd[], char postOd[], int n);
void PreOrder(BTree bt);
int main()
{
char inOd[N], postOd[N]; /* 中序序列与后序序列 */
int n = 0;
char ch;
while ((ch = getchar()) && ch != 'n')
inOd[n++] = ch;
n = 0;
while ((ch = getchar()) && ch != 'n')
postOd[n++] = ch;
BTree bt = CreateBTree(inOd, postOd, n);
PreOrder(bt);
printf("n");
return 0;
}
BTree CreateBTree(char inOd[], char postOd[], int n)
{
if (n == 0)
return NULL;
BTree btRoot = new BTNode;
btRoot->data = postOd[n-1]; //后序序列最后一个元素一定是根节点
char lInOd[N], rInOd[N];
char lPostOd[N], rPostOd[N];
int n1, n2;
n1 = n2 = 0;
//根据根节点将中序序列分为左子树和右子树
for (int i = 0; i < n; i++)
{
if (i <= n1 && inOd[i] != btRoot->data)
lInOd[n1++] = inOd[i];
else if (inOd[i] != postOd[n-1])
rInOd[n2++] = inOd[i];
}
//根据一个树的后序序列的长度等于中序序列且后序遍历是先左子树再右子树
//将后序序列分为左子树和右子树
int m1, m2;
m1 = m2 = 0;
for (int i = 0; i < n-1; i++)
{
if (i < n1)
lPostOd[m1++] = postOd[i];
else
rPostOd[m2++] = postOd[i];
}
btRoot->lChild = CreateBTree(lInOd, lPostOd, n1);
btRoot->rChild = CreateBTree(rInOd, rPostOd, n2);
return btRoot;
}
void PreOrder(BTree bt)
{
if (bt != NULL)
{
printf("%c", bt->data);
PreOrder(bt->lChild);
PreOrder(bt->rChild);
}
}
4. 根据不完整的先序,中序,后序序列
如果同时给出先序,中序,后序三种序列,但都是不完整的,能否建立一课二叉树呢?考虑下面一个例子:
一棵二叉树的先序、中序和后序序列分别如下,其中一部分未显示出来,试编程求出空格处的内容。
先序:_B_F_ICEH_G
中序:D_KFIA_EJC_
后序:_K_FBHJ_G_A
事实上,上述例子的核心思想还是方式三中先找到根节点,再分为左右子树,然后递归进行。区别是这里不能唯一的根据先序或后序来确定根节点,故需要判断当前是先序序列还是后序序列可以得到根节点,所以函数实现需要传递先序中序后序3种序列。而此题还有一个隐含的条件,就是当先序和后序都不能得到根节点时,中序序列存在且只存在一个'_',而且'_'就是根节点所在位置。这样分析之后代码就比较好实现了。代码如下:
/*
一棵二叉树的先序、中序和后序序列分别如下,其中一部分未显示出来,
试根据三个不完整的序列建树,然后依次输出先,中,后序的完整序列。
输入:
_B_F_ICEH_G
D_KFIA_EJC_
_K_FBHJ_G_A
输出:
ABDFKICEHJG
DBKFIAHEJCG
DKIFBHJEGCA
*/
#include <cstdio>
#include <cstdlib>
using namespace std;
const int N = 1010;
typedef struct BTNode *Position;
typedef Position BTree;
struct BTNode
{
char data;
Position lChild, rChild;
};
BTree CreateBTree(char preOd[], char inOd[], char postOd[], int n);
void PreOrder(BTree bt);
void InOrder(BTree bt);
void PostOrder(BTree bt);
int main()
{
char preOd[N], inOd[N], postOd[N];
int n = 0;
char ch;
while ((ch = getchar()) && ch != 'n')
preOd[n++] = ch;
n = 0;
while ((ch = getchar()) && ch != 'n')
inOd[n++] = ch;
n = 0;
while ((ch = getchar()) && ch != 'n')
postOd[n++] = ch;
BTree bt = CreateBTree(preOd, inOd, postOd, n);
PreOrder(bt);
printf("n");
InOrder(bt);
printf("n");
PostOrder(bt);
printf("n");
return 0;
}
BTree CreateBTree(char preOd[], char inOd[], char postOd[], int n)
{
if (n == 0)
return NULL;
BTree btRoot = new BTNode;
if (n == 1)
{
if (preOd[0] != '_')
btRoot->data = preOd[0];
else if (inOd[0] != '_')
btRoot->data = inOd[0];
else if (postOd[0] != '_')
btRoot->data = postOd[0];
else
{
printf("Input error!n");
exit(0);
}
btRoot->lChild = NULL;
btRoot->rChild = NULL;
return btRoot;
}
if (postOd[n-1] != '_')
btRoot->data = postOd[n-1]; //后序序列最后一个元素一定是根节点
else if (preOd[0] != '_')
btRoot->data = preOd[0];
else
{
printf("Input Error!n");
exit(0);
}
char lPreOd[N], rPreOd[N];
char lInOd[N], rInOd[N];
char lPostOd[N], rPostOd[N];
int n1, n2;
n1 = n2 = 0;
//根据根节点将中序序列分为左子树和右子树
int flag = 0; //判断根节点是否在中序序列中
for (int i = 0; i < n; i++)
{
if (inOd[i] == btRoot->data)
{
flag = 1;
break;
}
}
if (flag == 1) //如果根节点存在,按根节点划分
{
for (int i = 0; i < n; i++)
{
if (i <= n1 && inOd[i] != btRoot->data)
lInOd[n1++] = inOd[i];
else if (inOd[i] != btRoot->data)
rInOd[n2++] = inOd[i];
}
}
else //如果根节点不存在,按'_'划分
{
for (int i = 0; i < n; i++)
{
if (i <= n1 && inOd[i] != '_')
lInOd[n1++] = inOd[i];
else if (inOd[i] != '_')
rInOd[n2++] = inOd[i];
}
}
//根据一个树的后序序列的长度等于中序序列且后序遍历是先左子树再右子树
//将后序序列分为左子树和右子树
int m1, m2;
m1 = m2 = 0;
for (int i = 0; i < n-1; i++)
{
if (i < n1)
lPostOd[m1++] = postOd[i];
else
rPostOd[m2++] = postOd[i];
}
//根据一个树的先序序列的长度等于中序序列且先序遍历是除根节点外也是先左子树再右子树
//将先序序列分为左子树和右子树
m1 = m2 = 0;
for (int i = 1; i < n; i++)
{
if (i < n1 + 1)
lPreOd[m1++] = preOd[i];
else
rPreOd[m2++] = preOd[i];
}
btRoot->lChild = CreateBTree(lPreOd, lInOd, lPostOd, n1);
btRoot->rChild = CreateBTree(rPreOd, rInOd, rPostOd, n2);
return btRoot;
}
void PreOrder(BTree bt)
{
if (bt != NULL)
{
printf("%c", bt->data);
PreOrder(bt->lChild);
PreOrder(bt->rChild);
}
}
void InOrder(BTree bt)
{
if (bt != NULL)
{
InOrder(bt->lChild);
printf("%c", bt->data);
InOrder(bt->rChild);
}
}
void PostOrder(BTree bt)
{
if (bt != NULL)
{
PostOrder(bt->lChild);
PostOrder(bt->rChild);
printf("%c", bt->data);
}
}
- 黑客真的会毁了比特币吗?
- Java实现Http的Post、Get、代理访问请求
- MySQL(一)之MySQL简介与安装
- 无人值守,检测程序正常运行,遇故障则重启服务
- JS魔法堂:jsDeferred源码剖析
- JavaSE(八)之集合概述
- 浅谈PHP开发与Java开发的优劣势,还不知道学习方向的可以来看看
- KVM+Qemu+Libvirt实战
- 内核级虚拟化技术
- tomcat配置ROOT目录和多站点
- IntelliJ IDEA使用(一)基本设置与类、方法模板设置
- JS魔法堂:从void 0 === undefined说起
- Maven(三)在Eclipse中使用Maven与Maven坐标
- Nginx多站点设置及负载均衡
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Linux本地提权漏洞复现与检测思路
- 内容安全策略( CSP )
- [译] 优化 React APP 的 10 种方法
- 如何免登陆观看b站大会员番剧
- 聊聊越来越火的对象存储
- AJAX的基本原理及实例解析。
- Docker私有镜像仓库是什么?
- React Native布局详细指南
- 走进Golang之Context的使用
- 「Workshop」第十一期:降维
- 开始在 GitHub 上写博客
- 微信公众号菜单点击发送天气预报
- SAP CRM Fiori应用如何启用Sales Office和Sales Group两个字段
- 通过注册表调整 Windows 8 窗口边框宽度
- 在 Mac OS X 中创建和使用内存盘