前言:这算是在刷树题的第一篇blog,记录一下,方便以后复习
准备
- 先序遍历二叉树结果的第一个节点是根节点
- 中序遍历二叉树结果中左子树右子树又以根节点隔开
假定:
先序遍历结果为: A B D F G H I E C
中序遍历结果为: F D H G I B E A C
第一次考虑
毫无疑问通过先序遍历可以知道A是最开始的根节点,所以中序遍历中我们可以知道它的结构是这样的
再进一步对上图中的左子树进行考虑,现在就变成了
先序遍历结果B D F G H I E
中序遍历结果F D H G I B E
在这里我们先求出来新的先序遍历结果在原来先序遍历结果中的位置
如图
- i表示先序遍历结果的初始位置,j表示末尾
- k表示中序遍历结果的初始位置,H表示末尾
- m标识中序结果中的根节点
我们先看左子树的先序遍历结果位置:
我们可以看到先序遍历结果中B-E是分离后的左子树先序遍历结果,B的位置很好求就是i+1,
E的位置我们不妨设x,则有上下对齐m-k=x-i,得x=m-k+i
所以这次分离后的先序结果位置范围是[i+1,m-k+i]
再看左子树的中序遍历位置
我们可以看到上图中序遍历结果中F-E是分离后的左子树中序遍历结果,我们也可以通过设x的方式来求,得这次分离后的中序结果位置范围是[k,m-1]
接下来再看右子树的先序遍历结果位置:
同样是设x,最后范围是[m+j-h+1,j]
右子树的中序遍历结果位置:
[m+1,H]
第二次考虑
同理,由先序可知B为根节点,再去中序遍历结果中以B分离左子树FDHGI,右子树E,就变成了下图
再往下我就不列了,这样我们就可以还原二叉树,如果想要输出后序结果,直接后序遍历就行,如果需要求二叉树的高度,直接求就行
好了,道理懂了,我们就上代码叭
首先是二叉树结构定义
typedef struct bitnode
{
struct bitnode *lchild;
struct bitnode *rchild;
char data;
} BiTNode,*BiTree;
无论是树结构的定义还是先序后序遍历什么的,要想方便递归是离不开的
下面就是还原树的递归,其实就是对我们刚才原理方面的一个模拟
//两个string分别表示先序中序结果集的传参
void houzhong(string xianxu,int i,int j,string zhongxu,int k,int h,BiTree *t)
{
//m用于标志中序结果集里的根节点
int m;
//申请节点
*t =(BiTree)malloc(sizeof(BiTNode));
//将根节点的值给这个新节点
(*t)->data=xianxu[i];
//让m从中序结果集的第一个位置开始遍历,从而找到中序结果集中的那个根节点的位置
m=k;
while(zhongxu[m]!=xianxu[i])
m++;
//如果中序的第一个就是根节点,那说明还原后的左子树是空的
if(m==k)
(*t)->lchild=NULL;
else
houzhong(xianxu,i+1,m-k+i,zhongxu,k,m-1,&(*t)->lchild);
//如果中序的最后一个是根节点,那说明还原后的右子树是空的
if(m==h)
(*t)->rchild=NULL;
else
houzhong(xianxu,m+j-h+1,j,zhongxu,m+1,h,&((*t)->rchild));
}
我们怎么知道还原的成功与否呢
利用先序遍历一下还原好的这棵二叉树就好了,看看跟原来一样不
//用于测试是否还原成功的先序遍历方法
void preorder(BiTree bt )
{
if(bt ==NULL) return;
else
{
printf(" %c",bt->data);
preorder(bt->lchild);
preorder((bt->rchild));
}
}
运行一下
分别输入了先序中序,还原之后进行先序遍历,结果与输入的先序是一样的。
整体的一个代码是这样的:
#include <stdio.h>
#include <stdlib.h>
#include <bits/stdc++.h>
#define MAX 30
using namespace std;
//定义树的递归结构
typedef struct bitnode
{
struct bitnode *lchild;
struct bitnode *rchild;
char data;
} BiTNode,*BiTree;
/*
xianxu:先序遍历的结果
i:先序的起点
j:先序的终点
zhongxu:中序遍历的结果
k:中序的起点
h:中序的终点
BiTree:二叉树
*/
//递归的使用
void houzhong(string xianxu,int i,int j,string zhongxu,int k,int h,BiTree *t)
{
//m用于标志中序结果集里的根节点
int m;
//申请节点
*t =(BiTree)malloc(sizeof(BiTNode));
//将根节点的值给这个新节点
(*t)->data=xianxu[i];
//让m从中序结果集的第一个位置开始遍历,从而找到中序结果集中的那个根节点的位置
m=k;
while(zhongxu[m]!=xianxu[i])
m++;
//如果中序的第一个就是根节点,那说明还原后的左子树是空的
if(m==k)
(*t)->lchild=NULL;
else
houzhong(xianxu,i+1,m-k+i,zhongxu,k,m-1,&(*t)->lchild);
//如果中序的最后一个是根节点,那说明还原后的右子树是空的
if(m==h)
(*t)->rchild=NULL;
else
houzhong(xianxu,m+j-h+1,j,zhongxu,m+1,h,&((*t)->rchild));
}
//还原二叉树的方法
BiTree ReBiTree(string houxu,string zhongxu,int n)
{
BiTree root;
if(n<=0)
root=NULL;
else
//最开始初始位置就是0,末尾位置就是n-1
houzhong(houxu,0,n-1,zhongxu,0,n-1,&root);
return root;
}
//用于测试是否还原成功的先序遍历方法
void preorder(BiTree bt )
{
if(bt ==NULL) return;
else
{
printf(" %c",bt->data);
preorder(bt->lchild);
preorder((bt->rchild));
}
}
int main()
{
//定义一个空树
BiTree T;
int n;
string xianxu="";
string zhongxu="";
T = NULL;
cin>>n;
cin>>xianxu;
cin>>zhongxu;
T=ReBiTree(xianxu,zhongxu,n);
preorder(T);
return 0;
}
如果要输出后序二叉树:
void postorder(BiTree bt )
{
if(bt ==NULL) return;
else
{
preorder(bt->lchild);
preorder((bt->rchild));
printf(" %c",bt->data);
}
}