通过遍历序列构造二叉树(扩展二叉树的先序先序和中序后序和中序层序和中序)附可执行完整代码
Posted 薛定谔的猫ovo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通过遍历序列构造二叉树(扩展二叉树的先序先序和中序后序和中序层序和中序)附可执行完整代码相关的知识,希望对你有一定的参考价值。
二叉树的构造
可以构建一棵二叉树的几个方法:
- 扩展二叉树的先序遍历序列
- 前序遍历序列和中序遍历序列
- 后序遍历序列和中序遍历序列
- 层序遍历序列和中序遍历序列
注意,只有前序遍历序列和后序遍历序列是不能唯一的确定一棵二叉树的。
扩展二叉树的先序遍历序列构造二叉树
题目描述:
在二叉树的所有空指针位置加入虚拟结点,就构成扩展二叉树。二叉树原有的结点称为内结点,新增的虚拟节点称为外结点。
设已知扩展二叉树的先序遍历序列,并用在原二叉树中不可能出现的值作为虚拟结点的值,如 “#” 表示外结点的值。
设计一个算法,使用这样一个先序遍历序列,建立树的二叉链表。
算法思想:
每读入一个值,若该值为"#",则返回空,继续读入下一个值;如果该值不为"#",那么就为它建立结点,结点值为该值,然后将该结点作为根结点,其地址通过函数的引用型参数root直接链接到作为实际参数的指针中。然后分别对左、右子树递归的建立子树。
实现代码:
//扩展二叉树的先序遍历序列
void BuildTree_Pre(BNode * & root, char pre[], int & i){
if(pre[i] == '#'){ //外结点,即空结点
i++;
root = NULL;
}else{
root = (BNode *)malloc(sizeof(BNode)); //建立根结点
root->data = pre[i];
i++;
BuildTree_Pre(root->lchild, pre, i); //递归建立左子树
BuildTree_Pre(root->rchild, pre, i); //递归建立右子树
}
}
另外,还有一种写法请参照二叉树遍历应用之根据前序遍历建树
思路是一致的,如果不理解引用型参数的可以参照这篇文章中的写法。
实例:
如上图所示,所有结点值为"#"的结点位于原二叉树的空子树结点的位置,按照先序遍历所得到的先序遍历序列为ABC##DE#G##F###。
若要建立如上所示的二叉树,则输入就应为ABC##DE#G##F###。
这里给出可执行的完整代码,为了验证构造的二叉树,构造完二叉树后,再输出其层序遍历的结果。
#include<bits/stdc++.h>
using namespace std;
typedef struct BNode{
char data;
struct BNode *lchild;
struct BNode *rchild;
}BNode;
//扩展二叉树的先序遍历序列
void BuildTree_Pre(BNode * & root, char pre[], int & i){
if(pre[i] == '#'){ //外结点,即空结点
i++;
root = NULL;
}else{
root = (BNode *)malloc(sizeof(BNode)); //建立根结点
root->data = pre[i];
i++;
BuildTree_Pre(root->lchild, pre, i); //递归建立左子树
BuildTree_Pre(root->rchild, pre, i); //递归建立右子树
}
}
//层序遍历
void levelOrder(BNode *root){
queue<BNode *> treenode;
if(root != NULL)
treenode.push(root);
while(!treenode.empty()){
BNode *p = treenode.front();
treenode.pop();
printf("%c ",p->data);
if(p->lchild != NULL)
treenode.push(p->lchild);
if(p->rchild != NULL)
treenode.push(p->rchild);
}
}
int main(){
char pre[100];
BNode *root;;
scanf("%s",pre);
int i = 0;
BuildTree_Pre(root, pre, i);
levelOrder(root);
return 0;
}
执行结果:
先序遍历序列和中序遍历序列构造二叉树
题目描述:
给定一棵二叉树的先序遍历序列pre[s1…t1]和中序遍历序列in[s2…t2],设二叉树采用二叉链表存储,设计一个算法构造这棵二叉树。
算法思想:
算法的实现步骤如下:
1)根据先序遍历序列确定树的根结点;
2)根据根结点在中序序列中的次序划分出二叉树的左子树、右子树包含哪些结点,
然后根据左、右子树结点在先序序列中的次序确定子树的根结点,即回到步骤1)。
重复上述步骤,直到每棵子树仅有一个结点(该子树的根结点)为止。
如下图所示:
若前序遍历序列为:ABCDEFGHI
中序遍历序列为:BCAEDGHFI
实现代码:
//先序遍历和中序遍历建树
BNode *PreInCreate(char pre[], char in[], int s1, int t1, int s2, int t2){
//s1,t1为先序遍历序列的第一个结点和最后一个结点的下标
//s2,t2为中序遍历序列的第一个结点和最后一个结点的下标
//初始时s1=s2=0, t1=t2=n-1
BNode *root = (BNode *)malloc(sizeof(BNode)); //建立根结点
root->data = pre[s1]; //根结点
int i;
for(i=s2; in[i]!=root->data; i++); //找根结点在中序遍历序列中的位置
int llen = i-s2; //左子树长度
int rlen = t2-i; //右子树长度
if(llen != 0) //递归建立左子树
root->lchild = PreInCreate(pre, in, s1+1, s1+llen, s2, s2+llen-1);
else //左子树为空
root->lchild = NULL;
if(rlen != 0)//递归建立右子树
root->rchild = PreInCreate(pre, in, t1-rlen+1, t1, t2-rlen+1, t2);
else //右子树为空
root->rchild = NULL;
return root;
}
或者,也可以使用引用型参数进行实现,实现的思路是一致的。
void PreInCreate2(BNode *&root, char pre[], char in[], int s1, int t1, int s2, int t2){
if(s1<=t1){
root = (BNode *)malloc(sizeof(BNode));
root->data = pre[s1];
root->lchild = NULL;
root->rchild = NULL;
int i;
for(i=0; in[i]!=root->data; i++);
int llen = i-s2; //左子树长度
int rlen = t2-i; //右子树长度
PreInCreate2(root->lchild, pre, in, s1+1, s1+llen, s2, s2+llen-1); //递归建立左子树
PreInCreate2(root->rchild, pre, in, t1-rlen+1, t1, t2-rlen+1, t2); //递归建立右子树
}
}
这里给出可执行的完整代码,为了验证构造的二叉树,构造完二叉树后,再输出其层序遍历的结果。
#include<bits/stdc++.h>
using namespace std;
typedef struct BNode{
char data;
struct BNode *lchild;
struct BNode *rchild;
}BNode;
//层序遍历
void levelOrder(BNode *root){
queue<BNode *> treenode;
if(root != NULL)
treenode.push(root);
while(!treenode.empty()){
BNode *p = treenode.front();
treenode.pop();
printf("%c ",p->data);
if(p->lchild != NULL)
treenode.push(p->lchild);
if(p->rchild != NULL)
treenode.push(p->rchild);
}
}
//先序遍历和中序遍历建树
BNode *PreInCreate(char pre[], char in[], int s1, int t1, int s2, int t2){
//s1,t1为先序遍历序列的第一个结点和最后一个结点的下标
//s2,t2为中序遍历序列的第一个结点和最后一个结点的下标
//初始时s1=s2=0, t1=t2=n-1
BNode *root = (BNode *)malloc(sizeof(BNode)); //建立根结点
root->data = pre[s1]; //根结点
int i;
for(i=s2; in[i]!=root->data; i++); //找根结点在中序遍历序列中的位置
int llen = i-s2; //左子树长度
int rlen = t2-i; //右子树长度
if(llen != 0) //递归建立左子树
root->lchild = PreInCreate(pre, in, s1+1, s1+llen, s2, s2+llen-1);
else //左子树为空
root->lchild = NULL;
if(rlen != 0)//递归建立右子树
root->rchild = PreInCreate(pre, in, t1-rlen+1, t1, t2-rlen+1, t2);
else //右子树为空
root->rchild = NULL;
return root;
}
void PreInCreate2(BNode *&root, char pre[], char in[], int s1, int t1, int s2, int t2){
//s1,t1为先序遍历序列的第一个结点和最后一个结点的下标
//s2,t2为中序遍历序列的第一个结点和最后一个结点的下标
//初始时s1=s2=0, t1=t2=n-1
if(s1<=t1){
root = (BNode *)malloc(sizeof(BNode));
root->data = pre[s1];
root->lchild = NULL;
root->rchild = NULL;
int i;
for(i=0; in[i]!=root->data; i++);
int llen = i-s2; //左子树长度
int rlen = t2-i; //右子树长度
PreInCreate2(root->lchild, pre, in, s1+1, s1+llen, s2, s2+llen-1); //递归建立左子树
PreInCreate2(root->rchild, pre, in, t1-rlen+1, t1, t2-rlen+1, t2); //递归建立右子树
}
}
int main(){
char pre[100];
char in[100];
BNode *root;
BNode *root2;
int s1=0,s2=0;
int t1,t2;
scanf("%s",pre);
scanf("%s",in);
t1 = strlen(pre)-1;
t2 = strlen(in)-1;
root = PreInCreate(pre, in, s1, t1, s2, t2);
levelOrder(root);
printf("\\n");
PreInCreate2(root2, pre, in, s1, t1, s2, t2);
levelOrder(root2);
return 0;
}
执行结果:
后序遍历序列和中序遍历序列构造二叉树
题目描述:
给定一棵二叉树的后序遍历序列post[s1…t1]和中序遍历序列in[s2…t2],设二叉树采用二叉链表存储,设计一个算法构造这棵二叉树。
算法思想:
算法的实现步骤如下:
1)根据后序遍历序列确定树的根结点;
2)根据根结点在中序序列中的次序划分出二叉树的左子树、右子树包含哪些结点,
然后根据左、右子树结点在后序序列中的次序确定子树的根结点,即回到步骤1)。
重复上述步骤,直到每棵子树仅有一个结点(该子树的根结点)为止。
注意,这里与先序序列和中序序列构造二叉树的不同之处在于,先递归建立右子树,再递归建立左子树,这是由于
如下图所示:
若后序遍历序列为:CBEHGIFDA
中序遍历序列为:BCAEDGHFI
实现代码:
BNode *PostInCreate(char post[], char in[], int s1, int t1, int s2, int t2){
//s1,t1为后序遍历序列的第一个结点和最后一个结点的下标
//s2,t2为中序遍历序列的第一个结点和最后一个结点的下标
//初始时s1=s2=0, t1=t2=n-1
BNode *root = (BNode *)malloc(sizeof(BNode)); //建立根结点
root->data = post[t1]; //根结点
int i;
for(i=s2; in[i]!=root->data; i++); //找根结点在中序遍历序列中的位置
int llen = i-s2; //左子树长度
int rlen = t2-i; //右子树长度
if(llen != 0) //递归建立左子树
root->lchild = PostInCreate(post, in, s1, s1+llen-1, s2, s2+llen-1);
else //左子树为空
root->lchild = NULL;
if(rlen != 0) //递归建立右子树
root->rchild = PostInCreate(post, in, t1-rlen, t1-1, t2-rlen+1, t2);
else //右子树为空
root->rchild = NULL;
return root;
}
或者,也可以使用引用型参数进行实现,实现的思路是一致的。
void PostInCreate2(BNode *&root, char post[], char in[], int s1, int t1, int s2, int t2){
//s1,t1为后序遍历序列的第一个结点和最后一个结点的下标
//s2,t2为中序遍历序列的第一个结点和最后一个结点的下标
//初始时s1=s2=0, t1=t2=n-1
if(s1<=t1){
root = (BNode *)malloc(sizeof(BNode));
root->data = post[t1];
root->lchild = NULL;
root->rchild = NULL;
int i;
for(i=0; in[i]!=root->data; i++); //找中序遍历序列中的根结点的位置
int llen = i-s2; //左子树长度
int rlen = t2-i; //右子树长度
PostInCreate2(root->lchild, post, in, s1, s1+llen-1, s2, s2+llen-1); //递归建立左子树
PostInCreate2(root->rchild, post, in, t1-rlen, t1-1, t2-rlen+1, t2); //递归建立右子树
}
}
这里给出可执行的完整代码,为了验证构造的二叉树,构造完二叉树后,再输出其层序遍历的结果。
#include<bits/stdc++.h>
using namespace std;
typedef struct BNode{
char data;
struct BNode *lchild;
struct BNode *rchild;
}BNode;
//层序遍历
void levelOrder(BNode *root){
queue<BNode *> treenode;
if(root != NULL)
treenode.push(root);
while(!treenode.empty()){
BNode *p = treenode.front();
treenode.pop();
printf("%c ",p->data);
if(p->lchild != NULL)
treenode.push(p->lchild);
if(p->rchild != NULL)
treenode.push(p->rchild);
}以上是关于通过遍历序列构造二叉树(扩展二叉树的先序先序和中序后序和中序层序和中序)附可执行完整代码的主要内容,如果未能解决你的问题,请参考以下文章
已知二叉树的先序序列和中序序列怎么求后序序列?不是基于C++的,要在TC环境下能运行的,各位能人帮帮忙吧