PAT A1119 Pre- and Post-order Traversals【先序遍历、后序遍历求中序遍历】

这道题给出前序遍历、后序遍历,要求你求出中序遍历。
我的思路是:根据前序遍历和后序遍历建树,然后中序遍历,求出答案。
那么如何建树呢?从左到右遍历前序遍历数组中的全部节点,对于当前节点,检查它和上一个节点之间的关系。关系可以分为两大类:

  • 如果当前节点的后序遍历下标在上一个节点的左边,那么当前节点是上一个节点的子节点。那么,是左儿子还是右儿子呢?

    • 如果在后序遍历序列中,当前节点的下标等于上一个节点的下标减一,那么不确定是左儿子还是右儿子,树不唯一,在我的算法中,统一都设为左儿子,这对后续计算有帮助。
    • 如果在后序遍历序列中,当前节点的下标不等于上一个节点的下标减一,那么是左儿子。
  • 如果当前节点的后序遍历序列下标在上一个节点的右边,那么当前节点可能是上一个节点的兄弟节点,也可能是上一个节点的父亲、爷爷、曾祖父……的兄弟节点。具体是哪一个呢?这就要在建树的时候,多定义一个域保存全部节点的父节点了。从当前节点的父亲节点开始向上寻找,寻找到的第一个还没有右儿子节点,且在后序遍历数组中下标大于当前节点的节点,就是当前节点的父节点,直接把当前节点放在它的右儿子处即可。

本题注意的地方:

  1. 最后输出的时候,说了不可以有多余空格,但是我即使控制了不可以有多余空格,还是格式错误,最后找了网上的资料,才发现是还需要输出回车,额,说实话,pat考试要是遇到这样的题,那还不得自闭死
  2. 保存数据的时候,要保存左儿子,右儿子,父亲,以及节点的id,虽然题目中给出的序列中,节点大小全是1到n的,但是实际上可能并不是这样,所以不可以把输入的序列中的节点的值当作下标来使用,需要作为id保存起来。
  3. 本题中n的范围是30,数组没必要开成我这么大,我只是想开大一点试试而已,但是并没有多过一个点,我也懒得改回去了
  4. 我是利用递归实现的建树,但是我的思路其实利用数组循环也可以实现。
  5. 在最后递归中序遍历输出答案的时候,由于不能输出最后一个空格,要把答案保存起来,统一输出。
#include <iostream>
#include<vector>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#include<cstdlib>
#include<queue>
#include<cstring>
#include<set>
#include<list>
#include<unordered_set>
using namespace  std;
int n;
int qian[100010],hou[100010];
struct Node
{
    int l=0,r=0,id=0,fa=0,houIndex=0;
}t[100010];
int equalIndex[100010];
int cnt=0;
bool ans=true;
void search(int cnt1,int lastQianIndex,int lastHouIndex,int qianIndex,int houIndex)
{
    if(qianIndex>n)return;
    if(lastQianIndex==-1)
    {
        cnt++;
        t[cnt].id=qian[qianIndex];
        t[cnt].houIndex=houIndex;
        t[cnt].fa=-1;
        search(cnt,qianIndex,equalIndex[qianIndex],qianIndex+1,equalIndex[qianIndex+1]);
    }
    else{
        if(houIndex<lastHouIndex)
        {

            if(houIndex==lastHouIndex-1)
            {
                ans=false;
                cnt++;
                t[cnt].id=qian[qianIndex];
                t[cnt].fa=cnt1;
                t[cnt1].l=cnt;
                t[cnt].houIndex=houIndex;
            }
            else{
                cnt++;
                t[cnt].id=qian[qianIndex];
                t[cnt].houIndex=houIndex;
                t[cnt].fa=cnt1;
                t[cnt1].l=cnt;
            }
            search(cnt,qianIndex,equalIndex[qianIndex],qianIndex+1,equalIndex[qianIndex+1]);
        }
        else
            {
            int father=t[cnt1].fa;
            while(true)
            {

                if(t[father].r==0&&t[father].houIndex>houIndex)
                {
                    cnt++;
                    t[cnt].id=qian[qianIndex];
                    t[cnt].fa=father;
                    t[cnt].houIndex=houIndex;
                    t[father].r=cnt;
                    break;
                }
                else{
                    father=t[father].fa;
                }
            }
            search(cnt,qianIndex,equalIndex[qianIndex],qianIndex+1,equalIndex[qianIndex+1]);
        }

    }
}
vector<int>ansV;
void inOrder(int curr)
{
    if(t[curr].l>0)
    {
        inOrder(t[curr].l);
    }
    ansV.push_back(t[curr].id);
    if(t[curr].r>0)
    {
        inOrder(t[curr].r);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&qian[i]);
    for(int i=1;i<=n;i++)
        scanf("%d",&hou[i]);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
            if(hou[j]==qian[i])
            {
                equalIndex[i]=j;
                break;
            }
    }
    search(cnt,-1,-1,1,equalIndex[1]);

    if(ans)
        cout<<"Yes"<<endl;
    else
        cout<<"No"<<endl;

    inOrder(1);

    for(int i=0;i<ansV.size()-1;i++)
        cout<<ansV[i]<<" ";
    cout<<ansV.back()<<endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值