PAT A1119 Pre- and Post-order Traversals [前序后序求中序]

题目描述

链接
给出一棵树的结点个数n,以及它的前序遍历和后序遍历,输出它的中序遍历,如果中序遍历不唯一就输出No,且输出其中一个中序即可,如果中序遍历唯一就输出Yes,并输出它的中序

分析

  • 分析题目所给的正反样例,可以发现,最后递归到单一子树后,左根是它,右根也是它,就不唯一了。此时,可以随便指定为右孩子或者左孩子
  • 具体来说,对先序从前往后找,对后序从后往前找,找到左右子树的根,从而确定左右子树的范围进行递归
  • 当递归到某处,发现当前结点!!的左子树的根和右子树的根重合了\(i==prel+1\)话(\(i\)是右子树的根,\(prel\)是当前根结点,\(prel+1\)是左子树的根),则向下递归时,只向右子树递归
  • 另外还要注意,递归到最后,只剩一个结点即\(prel==prer\),就直接return root了,不用再向下递归了
  • 画下图,模拟下过程就好
#include<bits/stdc++.h>
using namespace std;

const int maxn = 40;
int pre[maxn],post[maxn];
int n;
struct node{
    int data;
    node *lchild,*rchild;
};
//root为后序序列的根结点,st,ed为先序的范围
vector<int> ans;
bool flag = true;
node *create(int prel, int prer, int postl, int postr){
    if(prel > prer) return NULL;
    //建立此状态下的根结点
    node *root = new node;
    root->data = pre[prel];
    root->lchild = NULL;
    root->rchild = NULL;
    if(prel==prer){
        return root;
    }
    //找左右子树的范围
    //在先序里面找到右子树根节点的位置
    int i;
    for(i=prel;i<=prer;i++){
        if(post[postr-1] == pre[i]){
            break;
        }
    }
    if(i - prel > 1){
        //左子树的范围: prel+1,i-1, 长度i-1-prel 
        root->lchild = create(prel+1,i-1,postl,postl+i-prel-2); //左子树的范围
        //右子树的范围: 
        root->rchild = create(i, prer, postl+i-prel-1, postr-1);
    }else{ //i==prel+1 即左右子树的根节点重合了
        flag = false;
        root->rchild = create(i, prer, postl+i-prel-1, postr-1); //就当成右子树
    }
    return root;
}

void inorder(node *root){
    if(!root) return;
    inorder(root->lchild);
    ans.push_back(root->data);
    inorder(root->rchild);
}

int main(){
    cin>>n;
    for(int i=0;i<n;i++) cin>>pre[i];
    for(int i=0;i<n;i++) cin>>post[i];
    node *root = create(0,n-1,0,n-1);
    inorder(root);
    if(flag) printf("Yes\n");
    else printf("No\n");
    for(int i=0;i<ans.size();i++){
        if(i==0)printf("%d",ans[i]);
        else printf(" %d",ans[i]);
    }
    printf("\n");
}

猜你喜欢

转载自www.cnblogs.com/doragd/p/11290774.html