输入:给出一个二叉树的前序遍历和中序遍历
输出:输出一个二叉树的后序遍历
题目链接:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_7_D
思路:前序遍历从头开始遍历的时候,第一个元素是根元素,根据这个元素,找到它在中序遍历中的位置,可以确定的是,这个元素在中序遍历序列中的位置,前面的都是这个根的左子树,后面的都是这个元素的右子树;比如对于前序{1,2,3,4,5},中序{3,2,4,1,5},前序的第一个元素是1,然后在中序遍历中找到它,那么说明{3,2,4}都是1的左子树,{5}是1的右子树。
对于左子树{3,2,4}而言,这是后序遍历,前序遍历是{2,3,4},那么2就是根元素,3是左子树,4是右子树。依次递归即可。
代码如下:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
#define ms(x, n) memset(x,n,sizeof(x));
typedef long long LL;
const LL maxn = 42;
int n, tag = 0;
vector<int> pre, in, post;
void rec(int l, int r){
if(l>=r) return;
int c = pre[tag++]; //preOrder遍历的下一个节点
int m = distance(in.begin(), find(in.begin(), in.end(), c)); //c在in中的位置
rec(l,m); //递归左子树
rec(m+1, r);//递归右子树
post.push_back(c);
}
int main()
{
int input;
cin >> n;
for(int i = 1; i <= n; i++)
cin >> input, pre.push_back(input);
for(int i = 1; i <= n; i++)
cin >> input, in.push_back(input);
rec(0, pre.size());
for(int i = 0; i < n; i++){
if(i) cout<<" ";
cout << post[i];
}
cout << endl;
return 0;
}
但是在已知前序和后序遍历的情况下,无法还原出中序遍历的树,看了一些博客,原因大概是只有前后序的情况下,有信息的重复,也有信息的丢失,只能反映出父子节点的关系,不能反映出左右的关系。
已知先序和后序,不能唯一确定二叉树;
已知先序或后序,而又知中序,则能唯一确定二叉树;
先序、中序相同时,二叉树没有左子树;
后序、中序相同时,二叉树没有右子树;
后序、先序相同时,只有一个根节点;
同理也可以写出,已知中序和后序遍历求前序遍历的方法,代码如下:
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> pre,in,post;
int root,pos;
void rec(int left,int right){
if(left>=right) return ;
int root=post[pos--];
int m=distance(in.begin(), find(in.begin(), in.end(),root));
rec(m+1,right);
rec(left,m);
pre.push_back(root);
return ;
}
void solve(int n){
pos=post.size()-1;
rec(0,n);
for(int i=n-1;i>=0;i--) {
if(i!=n-1) cout<<" "<<pre[i];
else cout<<pre[i];
}
cout<<endl;
return ;
}
int main (){
int n;
cin>>n;
int a;
for(int i=0;i<n;i++){
cin>>a;
in.push_back(a);
}
for(int i=0;i<n;i++){
cin>>a;
post.push_back(a);
}
solve(n);
return 0;
}