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;
}