非常经典的建树过程。
大概采用的思路是这样的。
根据后序确定子树根节点,中序得到左右节点,输出子树根节点
使用动态vector去存储中序,因为每次的中序长度不一样,后序静动态都可以。
每次更新的中序序列用queue存储
比如
一开始queue中有的中序是{{1 2 3 4 5 6 7}}
一回合后是{{1 2 3},{5 6 7}}
两回合后是{{2 3},{5},{7}}
后序:2 3 1 5 7 6 4,这里确定子树根节点为4,输出4
中序:1 2 3 4 5 6 7,将序列分为1 2 3,5 6 7
然后重复以上步骤就行,后序231,中序123,输出1。重复这样做。
这样的思想是广度优先遍历的思想,因为题目要求的是按层输出节点,那只能广度优先了。
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
int const N=1e5+10;
int n;
int main(){
cin>>n;
queue<vector<int>> m; //广度优先
vector<int> rv(n),v2(n);
for(int i=0;i<n;i++){
cin>>rv[i];
}
for(int i=0;i<n;i++){
cin>>v2[i];
}
m.push(v2);
int test=n;
// for(int i=0;i<v2.size();i++)cout<<v2[i]<<" ";
// puts("");
while(m.size()){
int root=-1;
vector<int> mv=m.front();//用b去对比m钟序列
m.pop();
//rv是后序的序列,mv是当前中序序列,
for(int it=0;it<rv.size();it++)
for(int i=0;i<mv.size();i++){
if(mv[i]==rv[it])
root=rv[it];
}
if(test--!=1)
cout<<root<<" ";
else
cout<<root<<endl;
//利用根去做分割
int j=-1;//记录根的下标,如果没有就是-1
if(mv.size()==1)continue;//如果只有一个数
for(int i=0;i<mv.size();i++){
if(mv[i]==root){
j=i;
}
}
//如果j==0,就跳过加入左边的序列
vector<int> tm;
if(j!=0){
for(int p=0;p<j;p++){
tm.push_back(mv[p]);
}
// for(int i=0;i<tm.size();i++)cout<<tm[i]<<" ";
// puts("");
m.push(tm);
}
vector<int> tm1;
//如果j==mv.size()-1,就跳过右边的序列
if(j!=mv.size()-1){
for(int k=j+1;k<mv.size();k++)
tm1.push_back(mv[k]);
// for(int i=0;i<tm1.size();i++)cout<<tm1[i]<<" ";
// puts("");
m.push(tm1);
}
}
}