PAT甲级 1020 Tree Traversals(25) (树的遍历)

该博客介绍了如何通过给定的二叉树后序和中序遍历序列来构建二叉树,并实现层序遍历。首先,利用后序遍历的最后一个元素作为根节点,然后根据中序遍历找到左右子树的划分。通过递归方式构建左右子树,并最终通过广度优先搜索(BFS)输出层序遍历序列。
摘要由CSDN通过智能技术生成

题目

Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder and inorder traversal sequences, you are supposed to output the level order traversal sequence of the corresponding binary tree.

输入

Each input file contains one test case. For each case, the first line gives a positive integer N (≤30), the total number of nodes in the binary tree. The second line gives the postorder sequence and the third line gives the inorder sequence. All the numbers in a line are separated by a space.

输出

For each test case, print in one line the level order traversal sequence of the corresponding binary tree. All the numbers in a line must be separated by exactly one space, and there must be no extra space at the end of the line.

样例输入 

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

样例输出 

4 1 6 3 5 7 2

题意理解

给你n个节点

先输入二叉树的后序遍历,再输入中序遍历

最后让你求层序遍历

那么我们直接建树,然后bfs一遍就能得到树的层序遍历

注意到中序遍历是 左 根 右 后序遍历是 左 右 根

那么我们存一下中序遍历每个点的位置是多少,中序遍历就是我们划分左右子树的关键

而后序遍历能帮我们确定哪个是根,没错,就是最后一个就是根节点

先构建树

il是中序遍历左端点 ir右端点

pl是后序遍历左端点 pr右端点

我们的根节点就是后序遍历的右端点 因为后序是 左右根 最后一个一定是这颗子树的根节点

然后我们找到根节点在中序遍历中的位置 我们根据根节点 来划分左右子树

如果此时根节点的位置k大于中序遍历的左端点 ,那么说明我们还没到左边的边界

此时我们还可以构建左子树

那么我们递归构建左子树 注意这里构建传入的边界

il 中序左端点 k-1右端点(中序根节点的左边一个位置)pl后序遍历左端点 

那么左子树的后序遍历右边界在哪呢

我们注意到因为中序的左子树长度等于后序左子树的长度 所以

k-1-il这就是中序遍历中左子树的长度

根节点-1再-中序遍历的左端点

这个长度加上pl就是后序遍历的右边界

所以左子树建树为

build(il,k-1,pl,k-il-1+pl)

右子树同样我们也递归建树

k+1 根节点右边一个位置就是右子树的中序左端点

ir 右端点

k-1-il之前我们已经分析过这是中序遍历中左子树的长度加上pl就是左子树的边界 

那么我们再加一 就是右子树的左边界了

pr-1就是我们后序根节点的前一个位置,此时这个位置是下一个右子树的根节点

所以右子树建树为

build(k+1,ir,k-il-1+pl+1,pr-1)

此时建立完整棵树了,那么我们跑一遍bfs就能获得这棵树的层序遍历了

代码 

#include<bits/stdc++.h>
using namespace std;
const int N=35;

unordered_map<int,int> pos;
unordered_map<int,int> l,r;
int postorder[35];//后序
int inorder[35];//中序
int n;
vector<int>ve;
int build(int il,int ir,int pl,int pr){
     int root=postorder[pr];
     int k=pos[root];
     if(k>il)l[root]=build(il,k-1,pl,k-il-1+pl);
     if(k<ir)r[root]=build(k+1,ir,k-il-1+pl+1,pr-1);
     return root;
}
void bfs(int root){
     queue<int>q;
     q.push(root);
     while(q.size()){
         int t=q.front();
         q.pop();
         ve.push_back(t);
         if(l.count(t))q.push(l[t]);
         if(r.count(t))q.push(r[t]);
     }
}
int main(){
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>postorder[i];
    }
    for(int i=0;i<n;i++){
        cin>>inorder[i];
        pos[inorder[i]]=i;
    }
    int root=build(0,n-1,0,n-1);
    bfs(root);
    for(int i=0;i<ve.size();i++){
        if(i)printf(" ");
        printf("%d",ve[i]);
    }
    puts("");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值