ALDS1_7_D: Reconstruction of the tree
限制时间:1s 内存限制:65536KB 正达率:41.38%
现在有两个节点序列,分别是对同一个二叉树进行前序和中序遍历的结果。请编写一个程序,输出该二叉树按后序遍历的节点序列。
输入:
第一行输入二叉树的节点数n
第二行输入前序遍历的节点编号序列,相邻编号用空格隔开
第三行输入中序遍历的节点编号序列,相邻编号用空格隔开
输出:
在一行输出按后序遍历时的节点编号序列。相邻节点编号用空格隔开
限制 1<=节点数<=100
输入示例:
5
1 2 3 4 5
3 2 4 1 5输出示例:
3 4 2 5 1
思路:
Preorder 按照 根–> 左子树–>右子树 的顺序递归遍历,Inorder按照 左子树–>根–>右子树 的顺序遍历。
Preorder 的输入为 pre ={1,2,3,4,5,6,7,8,9}
Inorder 的输入为 in ={3,2,5,4,6,1,8,7,9}
可以生成如图所示的二叉树:
首先,按Preorder遍历的顺序依次访问各节点。访问过程中,我们能通过in得知各子树内的Inorder遍历的顺序,从而重建以当前节点c为根的左子树和右子树。
Preorder遍历的当前节点为c,c在in中的位置为m,吗左侧就是c的左子树,右侧就是右子树。然后同理递归。
例如当前的节点为1,其在in中的位置为 3 2 5 4 6 [1] 8 7 9,那么当前树的根就是1,左右子树就是3 2 5 4 6 和8 7 9。接下来在3 2 5 4 6组成的树中,Preorder 遍历的下个节点 2 是 根(3 [2] 5 4 6) ,3 和5 4 6 是子树。
如果用in的下标 l 和 r 表示Preorder 当前访问的子树的范围(不包含r),那么这个递归函数可用如下的方法实现。
reconstruction(l, r)
if l >= r
return
c = next(pre) //Preorder 遍历的下一个节点
m = in.find(c) //在Inorder中的位置
reconstruction(l, m) //重建左子树
reconstruction(m+1 ,r) //重建右子树
print c //以Postorder遍历的顺序输出c
这个算法要对每层递归执行复杂度为O(n)的线性搜索,因此最坏的情况下复杂度为O(n^2)。
//c++
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;
int n, pos;
vector<int> pre,in,post;
void rec(int l, int r){
if(l >= r) return;
int root = pre(pos++);
int m = distance(in.begin(),find(in.begin(),in.end(),root))
rec(l, m);
rec(m+1, r);
post.push_back(root);
}
void solve(){
pos = 0;
rec(0, pre.size());
for(int i=0;i<n;i++){
if(i) cout<<" ";
cout<<post[i];
}
cout<<endl;
}
int main(){
int k;
cin >>n;
for(int i=0;i<n;i++){
cin >>k;
pre.push_back(k);
}
for(int i=0;i<n;i++){
cin>>k;
in.push_back(k);
}
solve();
return 0;
}