初见安~超级激动地自己写代码解决了这么个问题所以来发篇博客。
问题就如标题所示了。【还是放一下具体题面
Description
给出树的前序遍历及中序遍历,求其后序遍历。
Input
存在多组数据,请做到文件底结束
每组数据给出两个字符串,均不超过26个字母。分为前序、中序遍历。
Output
如题
Sample Input
DBACEGF ABCDEFG
BCAD CBAD
Sample Output
ACBFGED
CDAB
Sol
已知树的先序和中序,首先是一定可以确定一棵树的。至于如何处理,我们可以手动推一下试试。
再放一个样例——
Input2
ABDEGCF DBGEACF
Output2
DGEBFCA
首先我们第一反应——由先序遍历(根左右)可得:树的根节点为A。而中序遍历(左根右)首为D,可得:树的左半边是由A出发一路递归到了点D。而后B在先序中出现过,所以中序里的DB是在回溯;G没有在先序出现过,所以是B的右子树的内容了,E同理…………【剩下的自己去画吧。
如果这样找的话好像特判就特别多了。但是我们仔细观察上边的过程——我们一直在用中序找,以先序作为判定是根还是子树的参考。既然如此何不再简化先序的作用——用来找父亲节点。什么意思——后序遍历(左右根)的遍历方式其实类似于线段树,先左后右最后回溯至其父亲。如果我们找到了一个父亲节点,就相当于可以直接搜其两个儿子节点,遇到叶子节点直接输出即可。
可能你还是没怎么懂,我们用这个思路再找一遍吧——在上方的样例2中,首先由ABDEGCF可知根节点为A。我们发现在中序中A的下标为(从0开始)4,所以中序中[ 0, 3 ]为最大左子树,[ 5, 6 ]为最大的右子树。我们分别递归——在左子树DBGE中,由先序可得B为根节点,所以D为左子树,GE为右子树。当然,再往下一层D也不过是单点,所以可以直接输出了——最深最靠左的一个结点。GE的话在先序中我们D已经用过了,所以再往后看——是E,所以G为E的孩子,但是E出现在了这个子树的边界处,所以递归下去的只有G,输出,回溯,输出根节点E,再回溯,输出根节点B。这样以A为根节点的左子树就已经处理完了。右子树同理。所以——我们用一个递归就可以解决了。
下面就是代码啦~
#include<bits/stdc++.h>
using namespace std;
string s1, s2;
int now;
bool vis[30];//s1
map<char, int> m;
void find(int l, int r)
{
if(l == r)//叶子节点
{
printf("%c", s2[l]);
now++;//先序中直接下一位
return;
}
int mid = s2.find(s1[now]);//start from 0
now++;
if(mid > l) find(l, mid - 1);//否则mid为边界点,当做根节点处理,不必再递归
if(r > mid) find(mid + 1, r);
printf("%c", s2[mid]);//输出这一子树的根
}
int main()
{
while(cin >> s1 >> s2)
{
now = 0;
find(0, s1.size() - 1);
puts("");
}
return 0;
}
迎评:)
——End——