1127 ZigZagging on a Tree
题目大意
给出一个树的中序和后序遍历结果,求它的Z字型层序遍历,也就是偶数层从右往左,奇数层从左往右遍历
核心思路
- 利用后序序列的下标post_r作为结点编号index,联系数组post和二维数组tree(post[index]为当前结点的值)(tree[index][0]为当前结点的左孩子结点编号,tree[index][1]为当前结点的右孩子结点编号)。经过dfs后,得到存储了每个结点的左右孩子tree[index][0]和tree[index][1]的二维数组tree(每一层dfs中的结点编号index采用引用传递,传递给上一层的tree[index][0]或tree[index][1]或整棵树的根结点root)
- 利用结构体node存储这个结点的结点编号index和层号depth;二维数组result存储结点的层号和这一层的所有结点编号(下标为层号,值为这一层的所有结点编号)。经过bfs后将每个结点放到二维数组result中
- Z字形输出二维数组
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
int n;//结点数量
int tree[35][2],root;//记录每个结点的结点编号及其左右孩子的结点编号,根结点编号
vector<int> in,post;//中序序列,后序序列
void dfs(int &index,int in_l,int in_r,int post_l,int post_r){
if(in_l>in_r) return;//递归边界,表示上一层的结点的该孩子结点编号使用默认值0
//根结点编号index
index=post_r;
//找到当前根结点下标所对应的值在中序序列中的下标
int i=0;
while(in[i]!=post[post_r]) i++;
//根结点编号index所对应的左右孩子结点编号tree[index][0]、tree[index][1]
dfs(tree[index][0],in_l,i-1,post_l,post_l+(i-in_l)-1);
dfs(tree[index][1],i+1,in_r,post_l+(i-in_l),post_r-1);
}
struct node{
//当前结点的结点编号和所处的层次
int index;
int depth;
};
vector<int> result[35];//二维数组:下标为该结点所处的层次,值为该结点的结点编号
int maxdepth=0;//记录最大的层号
void bfs(){
queue<node> q;
q.push(node{root,0});
while(!q.empty()){
node temp=q.front();
result[temp.depth].push_back(temp.index);
maxdepth=max(maxdepth,temp.depth+1);
q.pop();
if(tree[temp.index][0]!=0) q.push(node{tree[temp.index][0],temp.depth+1});
if(tree[temp.index][1]!=0) q.push(node{tree[temp.index][1],temp.depth+1});
}
}
int main(){
//读入所有的数据
cin>>n;
in.resize(n+1),post.resize(n+1);
for(int i=1;i<=n;i++) cin>>in[i];
for(int i=1;i<=n;i++) cin>>post[i];
//dfs深度优先遍历构建树(结点编号使用后序序列的下标表示)
dfs(root,1,n,1,n);
//广度优先遍历把每个结点的层号和结点编号放到二维数组result里
bfs();
//按照之字形输出
cout<<post[result[0][0]];
for(int i=1;i<=maxdepth;i++){
if(i%2==1){//逆序输出
for(int j=0;j<result[i].size();j++){
cout<<" "<<post[result[i][j]];
}
}else{//顺序输出
for(int j=result[i].size()-1;j>=0;j--){
cout<<" "<<post[result[i][j]];
}
}
}
}