还原二叉树
若给出二叉树的前序和中序,或者给出二叉树的后序和中序,可以还原出唯一的二叉树。但给出前序和后序不可以。
1.前序和中序
递归算法
根据二叉树的前序序列和中序序列,还原二叉树。分析可知,前序序列的第一个元素是该二叉树的根结点,在中序序列中找到根结点的位置(下标),便可知道该二叉树的左右子树中各自结点的个数。据此,可将前序序列分为:根结点+左子树+右子树,将中序序列分为:左子树+根结点+右子树。问题又转化为,根据左右子树的前序序列和中序序列,分别还原二叉树(左右子树)。
- 前序序列第一个元素:根结点
- 利用根结点,划分前序序列和后序序列的左右子树
- 递归调用,还原左右子树
- 递归出口:左右子树为空树,即序列元素个数为0,左边界大于右边界
/*根据二叉树的前序和中序还原二叉树,递归算法,函数返回根结点*/
//设前序序列preorder[n+1],中序序列inorder[n+1],下标均为[1,n]
BiTNode *creat_Tree(int pre_L,int pre_R,int in_L,int in_R)
{
//pre_L,pre_R分别为前序序列的左右边界下标,in_L,in_R同理为中序序列的边界下标
if(pre_L>pre_R) return NULL;//递归出口,结点为空指针
int pos;//记录根结点的下标
for(int i=in_L;i<=in_R;i++)//在中序序列中找到根结点,记录下标
if(inorder[i]==preorder[pre_L])//根结点为前序序列第一个元素
{pos=i;break;}
//建立根结点
BiTNode *T=(BiTNode *)malloc(sizeof(BiTNode));
T->data=preorder[pre_L];
//还原左右子树
T->lchild=creat_Tree(pre_L+1,pre_L+pos-in+L,in_L,pos-1);
T->rchild=creat_Tree(pre_R-in_R+pos+1,pre_R,pos+1,in_R);
//函数返回根结点
return T;
}
2.后序和中序
递归算法
同理
- 后序序列最后一个元素:根结点
- 利用根结点,划分后序序列和后序序列的左右子树
- 递归调用,还原左右子树
- 递归出口:左右子树为空树,即序列元素个数为0,左边界大于右边界
/*根据二叉树的后序和中序还原二叉树,递归算法,函数返回根结点*/
//设后序序列postorder[n+1],中序序列inorder[n+1],下标均为[1,n]
BiTNode *creat_Tree(int post_L,int post_R,int in_L,int in_R)
{
//post_L,post_R分别为后序序列的左右边界下标,in_L,in_R同理为中序序列的边界下标
if(post_L>post_R) return NULL;//递归出口,结点为空指针
int pos;//记录根结点的下标
for(int i=in_L;i<=in_R;i++)//在中序序列中找到根结点,记录下标
if(inorder[i]==postorder[post_R])//根结点为前序序列第一个元素
{pos=i;break;}
//建立根结点
BiTNode *T=(BiTNode *)malloc(sizeof(BiTNode));
T->data=postorder[post_R];
//还原左右子树
T->lchild=creat_Tree(post_L,post_L+k-in_L-1,in_L,k-1);
T->rchild=creat_Tree(post_L+k-in_L,post_R-1,k+1,in_R);
//函数返回根结点
return T;
}
非递归算法
/*根据二叉树的后序和中序还原二叉树,非递归算法*/
#include<stdio.h>
//使用二叉树的顺序存储结构,二叉树所有结点存储在sqTree数组里
int sqTree[2001]={0}
int index_in[2001]={0};//存储对应结点i在中序序列inorder[]中的下标
int n;//结点总数
/*该函数将后序序列postorder[]中,从最后一个结点到第一个节点,一个个放入sqTree中*/
int put_root(int root,int inorder[],int postorder[]);
int main()
{
scanf("%d", &n);
int inorder[n+1],postorder[n+1];//中序序列和后序序列
int lastnode=1;//二叉树在数组中最后一个结点的下标
//初始化存储单元为0
for(int i=0;i<1001;i++)
{
sqTree[i]=0;
index_in[i]=0;
}
//输入后序序列,下标[1,n]
for (int i = 1; i <=n; i++)
scanf("%d", &postorder[i]);
//输入中序序列,下标[1,n]
for (int i = 1; i <=n; i++)
scanf("%d", &inorder[i]);
sqTree[1]=postorder[n];//根结点为后序序列最后一个元素
for(int i=1;i<=n;i++)//找到根结点在中序序列中的下标,存入index_in[1]
if(inorder[i]==sqTree[1])
{
index_in[1]=i;
break;
}
//还原二叉树
for(int i=n-1;i>=1;i--)
{
int k=put_root(postorder[i],inorder,postorder);
if(k>lastnode) lastnode=k;//lastnode为数组中最后一个结点的下标,用于输出
}
//按照层序输出二叉树
for(int i=0;i<lastnode;i++)
if(sqTree[i]!=0)//0为不存在该结点
printf("%d ",sqTree[i]);
printf("%d",sqTree[result]);
return 0;
}
/*该函数将后序序列postorder[]中,从最后一个结点到第一个节点,一个个放入sqTree中*/
int put_root(int root,int inorder[],int postorder[])
{
//后序序列中,从后往前的元素必为某个子树的根结点,根据其在中序序列的位置
int j,i=1;
for(int k=1;k<=n;k++)
if(inorder[k]==root)
{
j=k;break;
}
while(sqTree[i]!=0)
{
if(j>index_in[i])
i=2*i+1;
else if(j<index_in[i])
i=2*i;
}
index_in[i]=j;sqTree[i]=inorder[j];
return i;
}