PTA-GPLT L2-006 树的遍历(二叉树中序和后序输出层序遍历)

题目链接:https://pintia.cn/problem-sets/994805046380707840/problems/994805069361299456

L2-006 树的遍历 (25 分)

给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列。这里假设键值都是互不相等的正整数。

输入格式:

输入第一行给出一个正整数N(≤30),是二叉树中结点的个数。第二行给出其后序遍历序列。第三行给出其中序遍历序列。数字间以空格分隔。

输出格式:

在一行中输出该树的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。

输入样例:

7
2 3 1 5 7 6 4
1 2 3 4 5 6 7

输出样例:

4 1 6 3 5 7 2

二叉树基本结构

 用数组保存二叉树,从1开始,tree[1]为根节点的值。

如图,表示二叉树对应数组tree的下标。假设当前结点为i,那么2*i就是左子树,2*i+1就是右子树,i/2就是父结点(整数相除,向下取整)。例如对于3号结点,3*2=6,3*2+1=7,6和7分别是3的左右子树。6/2=3,7/2=3,6和7的父结点是3.

 

二叉树的后序遍历有一个特点,最后一个一定是根(前序遍历第一个一定是根)。因此,得到后序遍历,就确定了根。假设L是左子树,R是右子树,V是根,那么后序遍历是LRV,中序遍历是LVR。V确定了,就确定了L和R是什么。对L,把他当做一棵树,再按刚才的方法,后序遍历最后一个是根,递归做下去...

int k=0;
while(lrv[n-1]!=lvr[k]) k++;

这句就找到了根在中序遍历中的位置。中序就被分为左子树和右子树两个部分,用递归,把起点位置和长度传入就可以了

createTree(lrv,lvr,k,index*2);

对于左子树,在后序的起点是0,在中序的起点也是0,长度为k,因为是左子树,所以index*2。
createTree(lrv+k,lvr+k+1,n-k-1,index*2+1);

对于右子树,在后序的起点是k,在中序的起点是k+1,长度是n-k-1,右子树,所以index*2+1。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <list>
#include <vector>
#include <cmath>
#include <cstring>
#include <map>
#include <queue>

using namespace std;

int tree[10000],level[10000];//tree记录二叉树,level记录层序遍历
int sum;
int lvr[31],lrv[31];//lvr是中序,lrv是后序

void createTree(int *lrv,int *lvr,int n,int index) //后序和中序得到二叉树
{
    if(n==0) return;
    int k=0;
    while(lrv[n-1]!=lvr[k]) k++;
    tree[index] = lvr[k];
    createTree(lrv,lvr,k,index*2);
    createTree(lrv+k,lvr+k+1,n-k-1,index*2+1);
}

void LevelOrder() //层序遍历
    {
        queue <int> Q;
        Q.push(1);
        int p;
        while(!Q.empty())
        {
            p = Q.front(); Q.pop();
            level[sum] = tree[p]; sum++;
            if(tree[p*2]!=0) Q.push(p*2);  //如果为0,说明为NULL
            if(tree[p*2+1]!=0) Q.push(p*2+1);
        }
    }

int main() {
    int n; cin>>n;
    for(int i=0;i<n;i++) cin>>lrv[i];
    for(int i=0;i<n;i++) cin>>lvr[i];
    createTree(lrv,lvr,n,1);
    LevelOrder();
    for(int i=0;i<sum;i++){
        if(i==0) cout<<level[i];
        else cout<<" "<<level[i];
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值