遍历情况:
前序:根结点 ---> 左子树 ---> 右子树
中序:左子树---> 根结点 ---> 右子树
后序:左子树 ---> 右子树 ---> 根结点
例题一:
输入描述 Input Description
输入文件共2行,第一行表示该树的前序遍历结果,第二行表示该树的后序遍历结果。输入的字符集合为{a-z},长度不超过26。
输出描述 Output Description
输出文件只包含一个不超过长整型的整数,表示可能的中序遍历序列的总数。
样例输入 Sample Input
abc
cba
样例输出 Sample Output
4
思路:
由以上的前中后遍历顺序可以看出在已知前序遍历和后序遍历的情况下,中序遍历不是唯一确定的。而且中序遍历的不确定性是由一个节点(只有一边子树)的左右子树的不确定性决定的。例如前序遍历ab,后序遍历ba,a为根,b为子树,在中序遍历中如果b为左子树,则中序遍历为ba;如果b为右子树,则中序遍历为ab。所以当这种节点有n个时,中序遍历的可能性就有:2^n;
那么问题就转变为如果确定这种节点的数量。可以总结出一个规律,如上例。前序遍历为ab,后序遍历为ba,此时无法确定b是为左子树还是右子树,那么就产生了一个特殊节点。所以规律就是(此时a,b分别为前序遍历和后序遍历的字符串):a[i]==b[j]时,a[i+1]==b[j-1]则产生一个特殊节点
代码:
#include<iostream> #include<stdio.h> #include<math.h> #include<string.h> using namespace std; int main(){ string a,b; cin>>a; cin>>b; int cnt = 0; int len1 = a.length(); int len2 = b.length(); for(int i=0;i<len1;i++){ for(int j=1;j<len2;j++){ if(a[i]==b[j]&&a[i+1]==b[j-1]){ cnt++; } } } cout<<pow(2,cnt)<<endl; return 0; }
例题二:
输入:第一行输入二叉树的结点数n
第二行输入前序遍历的结点编号序列,相邻编号用空格隔开
第3行输入中序遍历的结点编号序列,相邻编号用空格隔开
结点编号为从1至n的整数,请注意,1不一定是根节点
输出:
在1行中输出按后序遍历时的结点编号序列。相邻结点编号之间用1个空格隔开。
限制:1<=结点数<=100
输入示例:
5
1 2 3 4 5
3 2 4 1 5
输出示例:
3 4 2 5 1
代码:
#include<iostream> #include<stdio.h> #include<vector> #include<algorithm> using namespace std; vector<int>pre,in,post; int n,pos; 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; }