2255:重建二叉树
总时间限制: 1000ms 内存限制: 65536kB
描述
给定一棵二叉树的前序遍历和中序遍历的结果,求其后序遍历。
输入
输入可能有多组,以EOF结束。
每组输入包含两个字符串,分别为树的前序遍历和中序遍历。每个字符串中只包含大写字母且互不重复。
输出
对于每组输入,用一行来输出它后序遍历结果。
样例输入
DBACEGF ABCDEFG
BCAD CBAD
样例输出
ACBFGED
CDAB
解析:巨难过,感觉自己写的没有错,但是一直runtime error,为什么!哪位大神给解释一下,感激不尽~第一个代码是自己写的,朴素的构造树来求的,第二个是某大神写的,巨简洁,膜拜一下
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
//http://bailian.openjudge.cn/practice/2255/
//Runtime Error 为什么!!!
struct node{
char val;
node *l,*r;
};
char a[1000000],b[1000000];
int len1,len2;
node *f(node *x,int l1,int l2,int r2){
//l1是前序左端点,l2,r2是后序左右端点
if(r2==l2)return x;//子树为空
char k=a[l1];// 根节点是前序第一个字符
x=new node;
x->val=k;
x->l=NULL;x->r=NULL;
if(r2-l2==1)return x;
int ll2,lr2,rl2,rr2;
for(int i=l2;i<r2;i++){
//从中序中找根节点,分出左右子树
if(b[i]==k){
ll2=l2;//左子树左端点
lr2=i;
rl2=i+1;//右子树左端点
rr2=r2;
break;
}
}
x->l=f(x->l,l1+1,ll2,lr2);
x->r=f(x->r,l1+1+(lr2-ll2),rl2,rr2);
}
void post(node *x){
if(x->l!=NULL)post(x->l);
if(x->r!=NULL)post(x->r);
cout<<x->val;
}
int main(){
while(scanf("%s %s",a,b)!=EOF){
len1=strlen(a);
len2=strlen(b);
node *root=NULL;
root=f(root,0,0,len2);
post(root);
cout<<endl;
}
}
http://www.cnbolgs.com/Peper/p/7241955.html
#include<stdio.h>
#include<string.h>
void bulid(int n,char s1[],char s2[])//n是树的节点数,s1是记录先序遍历,s2中序遍历
{
if(n<=0) return;//没有节点了,找到边界return
int p=strchr(s2,s1[0])-s2;
// strchr(s2,s1[0])是s2的地址+s1[0]第一次出现的位置i。s2是s2的地址
//所以p是 s1[0]第一次出现在s2中的位置
bulid(p,s1+1,s2);
//数的节点数为s1[0]在s2中之前的所有节点。s1+1是把s1数组整体向前移动一位(s1[0]是以前的s1[1],s1[1]改为以前s1[2]...
//以前s1[0]是根,现在不需要,所以删除。要它左子树的根节点
//s2不变(假设中序遍历中根节点的位置是a,那么后序遍历中0~a个点是树的左子树节点)
bulid(n-p-1,s1+p+1,s2+p+1);
//数的节点数为s1[0]在s2中之后的所有节点(因为数组从0开始,所以-1)
//以前s1[0]是根,现在不需要,左子树也不需要,所以都删除。要它右子树的根节点
//s2+p+1(假设中序遍历中根节点的位置是a,a~n-2(数组从0开始)个点是树的右子树节点 )
printf("%c",s1[0]);//输出
}
int main()
{
char s1[10007],s2[10007];//s1是树的前序遍历,s2是树的中序遍历
while(scanf("%s %s",s1,s2)!=EOF)//多组数据
{
bulid(strlen(s1),s1,s2);
printf("\n");//记得输出\n
}
return 0;
}/*
先序遍历第一个节点一定是根节点。
中序遍历根节点左侧就是树的左子树,右侧就是树的右子树。
后序遍历最后一个节点一定是根节点,而假设中序序列里根节点位置是m,那么
后序序列里0至m-1个节点是树的左子树节点,m至倒数第二个点是树的右子树节
点。
*/
今天又做这个题,又写了一个程序,AC了
#include<iostream>
#include<string.h>
using namespace std;
//http://bailian.openjudge.cn/practice/2255/
//第一次忘记返回的判断了,想明白了就是对两个数组分段进行递归处理
//每次根据前序中找到根节点,然后对中序左右分别处理直到空
char a[10000],b[10000];
int len1,len2;
void f(int l,int l2,int r2){
if(l2==r2)return;
char k=a[l];//前序中的第一个值是根节点
int rr;
for(int i=l2;i<r2;i++){
if(b[i]==k){
rr=i;
break;//rr左边是左子树,右边是右子树
}
}
f(l+1,l2,rr);
f(l+(rr-l2+1),rr+1,r2);
cout<<k;
}
int main(){
while(cin>>a>>b){
len1=strlen(a);
len2=strlen(b);
f(0,0,len2);
cout<<endl;
}
}