1119 Pre- and Post-order Traversals (30 分)根据前序后序来建树再中序输出

1119 Pre- and Post-order Traversals (30 分)

不采用柳神的方式来做,柳神的太牛了,平常人看不懂。我就按照正常的建树规则来建树。
想要作出这种题,你需要自己先思考,把前序和后序画出来,自己建树构建一下,多加思考映像才能深刻。

思路:

很显然,前序的第一个值和后序的最后一个值是一样的。设置前序的左边为prel,右边为prer。后序的左边为postl,右边为postr。 那么可以发现前序中prel+1的下标值肯定是左子树的节点,后序的prer-1肯定是右子树的节点。通过这样我们可以确定左右节点,从而确定左右子树的区间。
但是如果前序的prel+1和后序的postr-1所对应的值相等,那么我们就不能区别是左子树还是右子树。所以这个地方就要另外考虑,当遇到这种值相等的情况我们可以设置设置一个flag 表示遇到多种情况的可能。然后默认选择左子树或者右子树来做即可。

可以采用如下的输入来试着自己构建树,并按照代码和上述思路来分析:
前序:1 2 3 4
后序:2 4 3 1

下面附上代码,配有详细的注释:

#include<iostream>
#include<vector>
using namespace std;
struct Node{
    int val;
    Node*left,*right;
    Node(int v){
        val=v;
        left=right=NULL;
    }
};
vector<int>preorder,postorder;
bool flag=false;
Node*create(int prel,int prer,int postl,int postr){
    if(prel>prer||postl>postr) return NULL;
    Node*root=new Node(preorder[prel]);
    if(prel==prer||postl==postr) return root; //防止数组越界  因为相等的时候就只有一个了直接返回即可
    int k1,k2;  //这里k1是找右子树在前序中的位置  k2是指在后序中找左子树的位置。
    for(k1=prel;k1<=prer;k1++){
        if(preorder[k1]==postorder[postr-1]){ //postr-1 根据后序遍历的规则就是右子树的节点 ,,所以要在前序遍历中找到位置k1
            break;
        }
    }
    for(k2=postr;k2>=postl;k2--){ 
        if(postorder[k2]==preorder[prel+1]) break; //prel+1根据前需遍历的规则就是左子树的节点 ,所以要再后序遍历找到位置k2
    }
    if(preorder[prel+1]!=postorder[postr-1]){ 
        root->left=create(prel+1,k1-1,postl,k2);
        root->right=create(k1,prer,k2+1,postr-1);
    }else{
        flag=true;//如果相等 说明不知道是左节点还是右节点。 这里默认当作左节点 ,即右子树不存在了
        root->left=create(prel+1,prer,postl,k2); //这里第二个参数 不再是k1-1 因为已经找不到k1即右子树不存在
        root->right=NULL;      
    }
    return root;
}
int cnt=0;
void inorder(Node*root){
    if(root==NULL) return;
    inorder(root->left);
    if(cnt==0) cout<<root->val;
    else cout<<" "<<root->val;
    ++cnt;
    inorder(root->right);
}
int main(){
    int n,x;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>x;
        preorder.emplace_back(x);  //1 2 3 4
    }
    for(int i=0;i<n;i++){
        cin>>x;
        postorder.emplace_back(x);//2 4 3 1
    }
    Node*root=create(0,n-1,0,n-1);
    if(flag) cout<<"No"<<endl;
    else cout<<"Yes"<<endl;
    inorder(root);
    cout<<endl;
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值