2255:重建二叉树

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;
    }
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值