题目链接:Tree Recovery - UVA 536 - Virtual Judge (vjudge.net)
这个题,考察了二叉树的遍历和递归的融合运用,对于二叉树的遍历规则不熟悉的,这个题可能会很难理解,特别是又结合上递归,更加难以理解了,我想先从二叉树的遍历规则开始说起,这样可能会容易接受一点,
1,先序遍历:即根-左节点-右节点,先序遍历的特点是第一个元素就是其实就是根节点,与后序遍历恰好相反,
2.中序遍历:这个基本找不出规律
奇妙的是,题目里给出的是先序和中序遍历,相当于知道了根节点(先序遍历的第一个元素),还有根节点的左右大子树,就是中序遍历中的根节点的左右两部分,这样一来,结合递归可以找到相同的步骤,
拿第一个样例来看:
先序遍历:DBACEGF
中序遍历:ABCDEFG
那么接下来就是先找头结点,由于先序遍历中第一个元素即为头结点
D
| |
ABC EFG //在中序遍历中找到头结点,左右两侧即为左右两大颗子树
| |
B E//再次在先序遍历中找到最先出现的元素
| |
AC FG
| | | |
A C 空 FG//因为先序遍历中为EGF节点为E,而中序遍历中E的左边没有元素,为空
|
G
| |
F 空//因为中华序遍历中F在G的前面,表示F是G的左子树
这样一来整棵树就可以确定了,
这里需要注意每次将中序遍历中的某一个子树中的元素在先序遍历中查找根节点时,要对查找范围进行限制(因为每次要在遍历完左右子树的时候输出根节点),相当于把查找范围缩小,
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <sstream>
#include <cmath>
#define maxm 200+10
using namespace std;
string s,s1;
void dfs(int a,int b,int c,int d)
{
if(a>b||c>d)
return ;
for(int i=c;i<=d;i++)
{
if(s1[i]==s[a])
{
//dfs(a+1,a+i-c,c,i-1);
//dfs(a+i-c+1,b,i+1,d);
dfs(a+1,a+i,c,i-1);//先序遍历找到节点后,紧挨着的元素就是左子树部分,但是如何确定这个左子树的长度,就要靠中序遍历找到的根节点的位置,因为根节点的左侧部分就是左子树部分,也就是根节点的位置决定了查找的长度,假设中序遍历中查找到根节点的位置为i,则下次查找1其左子树时就可以确定i个长度这i个长度包含的元素一定是中序遍历中左子树的元素集合
dfs(a+i+1-c,b,i+1,d);//对于右子树来说,查找的元素应该从根节点的右边第一个出发,
break;
}
}
cout<<s[a];
}
int main()
{
while(cin>>s>>s1)
{
dfs(0,s.length()-1,0,s.length()-1);
cout<<endl;
}
return 0;
}