题意:已知先序和中序,将后序求出来
Little Valentine liked playing with binary trees very much. Her favorite game was constructing randomly looking binary trees with capital letters in the nodes.
This is an example of one of her creations:
D/ \/ \B E/ \ \/ \ \A C G//F
To record her trees for future generations, she wrote down two strings for each tree: a preorder traversal (root, left subtree, right subtree) and an inorder traversal (left subtree, root, right subtree). For the tree drawn above the preorder traversal is DBACEGF and the inorder traversal is ABCDEFG.
She thought that such a pair of strings would give enough information to reconstruct the tree later (but she never tried it).
Now, years later, looking again at the strings, she realized that reconstructing the trees was indeed possible, but only because she never had used the same letter twice in the same tree.
However, doing the reconstruction by hand, soon turned out to be tedious.
So now she asks you to write a program that does the job for her!
Input
The input will contain one or more test cases.
Each test case consists of one line containing two strings preord and inord, representing the preorder traversal and inorder traversal of a binary tree. Both strings consist of unique capital letters. (Thus they are not longer than 26 characters.)
Input is terminated by end of file.
Output
For each test case, recover Valentine's binary tree and print one line containing the tree's postorder traversal (left subtree, right subtree, root).
Sample Input
DBACEGF ABCDEFG
BCAD CBAD
Sample Output
ACBFGED
CDAB
提供三种解法:
前序遍历:根左右
中序遍历:左根右
后序遍历:左右根
例如上图:
前序遍历:ABEHFCGI
中序遍历:HEBFACIG
1 思路:
前序遍历第一个字母A,必定是这树的根节点。
在中序遍历中找到A的位置,把中序遍历分成两个子树:HEBF和CIG,
取前序遍历中的第二个点B,在分成的两个子树中找到B的位置,再次分成两个子树。HE和F,以此类推,分到不能再分了。
回溯到A点,对右子树CIG进行同样的操作。
#include<cstdio>
#include<cstring>
char be[100],en[100];
int n;
void build(int t1,int t2)
{if(t1>t2)return;n++;int u=strchr(en,be[n])-en;build(t1,u-1);build(u+1,t2);/*分为左子树和右子树区间分别查找*/printf("%c",en[u]);
}
int main()
{while(~scanf("%s%s",be,en)){n=-1;build(0,strlen(be)-1);printf("\n");}return 0;
}
2
思路:
前序遍历第一个字母A,必定是这树的根节点。
在中序遍历中找到A的位置,把中序遍历分成两个子树:HEBF和CIG,
根据A的位置,在前序中找到分界点(分界点+1=右节点)j=l1+(i-l2); 确定左子树和右子树在先序遍历的分界点j,即右子树的父节点
后序遍历:左右根,故用栈存入根右左节点
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stack>
using namespace std;
char w[10010],s[10010];
int n,pre[10010],in[10010]; //先序数组和后序数组
stack<int> st; //存放父节点void build(int l1,int r1,int l2,int r2) //l1,r1,是先序遍历的数组的开始和末尾,l2,r2是中序遍历的数组的开始和末尾
{int i,j;st.push(pre[l1]); //父节点入栈for(i=l2; i<=r2; i++)if(in[i]==pre[l1]) //找到父节点在中序遍历的位置ibreak;j=l1+(i-l2+1); //确定左子树和右子树在先序遍历的分界点j,即右子树的父节点if(j<=r1 && i+1<=r2) //求解右子树build(j,r1,i+1,r2);if(l1+1<=j-1 && l2<=i-1) //求解左子树build(l1+1,j-1,l2,i-1);
}int main()
{while(~scanf("%s",w)){int n=strlen(w);for(int i=0; i<n; i++)pre[i]=w[i]-'A';scanf("%s",s);for(int i=0; i<n; i++)in[i]=s[i]-'A';build(0,n-1,0,n-1);while(!st.empty()){printf("%c",st.top()+'A');st.pop();}printf("\n");}return 0;
}
3
利用递归,从前序一个个元素开始,m=1; 在中序中找到in[i] == pre[m],
然后将中序分为两部分,in[1.....i-1] 和in[i+1.....n],然后分别遍历这两
部分,直到这两部分元素为0(s>t) 或1个(s==t);
1.左子树 ,左子树范围必定在begin到i-1之间,下一个根的位置在root+1
2.右子树,右子树范围必定在i+1到end之间,根的位置就是(i-begin)是左子树
的大小,相当于root位置往后移左子树的个数再加一
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int M=1e3+10;
int a[M],b[M];
int n;
void dfs(int x,int y,int root)
{int i;if(x>y) return ;for(i=x;i<=y;i++)if(a[root]==b[i])break;dfs(x,i-1,root+1);dfs(i+1,y,root+(i-x)/**左子树大小*/+1);/**右子树,右子树范围必定在i+1到end之间,根的位置就是(i-begin)是左子树的大小,相当于root位置往后移左子树的个数再加一*/printf("%d%c",a[root],root==1?'\n':' ');
}
int main()
{while(~scanf("%d",&n)){for(int i=1;i<=n;i++)scanf("%d",&a[i]);for(int i=1;i<=n;i++)scanf("%d",&b[i]);dfs(1,n,1);}return 0;
}