以SDUTOJ1291数据结构上机测试4.1:二叉树的遍历与应用1为例
https://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Contest/contestproblem/cid/2711/pid/1291
思路:
递归实现,化解子问题解决。
先序:ABDCEF
中序:BDAECF
第一步:根据先序遍历的特点,我们可以简单地知道根节点为A
第二步:观察中序,其中root节点A左侧的BD必然是root的左子树,A右侧的ECF必定是root的右子树
第三步:观察左子树BD,左子树中的根节点必定是大树的leftchild。在先序中大树的leftchild位于root之后,所以左子树的根节点是B。
第四步:同理,root的右子树的节点ECF中的根节点也可以通过前序遍历得到。root的右子树节点ECF中的根节点也可以通过前序遍历求得。在前序遍历中,一定是先把root和root的所有左子树节点遍历完之后才会遍历右子树,并且遍历的左子树的第一个节点就是左子树的根节点。同理,遍历的右子树的第一个节点就是右子树的根节点。
第五步,观察发现,上面的过程是递归的。先找到当前树的根节点,然后划分为左子树,右子树,然后进入左子树重复上面的过程,然后进入右子树重复上面的过程。最后就可以还原一棵树了。该步递归的过程可以简洁表达如下:
1 确定根,确定左子树,确定右子树。
2 在左子树中递归。
3 在右子树中递归。
4 打印当前根。
代码实现
#include <bits/stdc++.h>
using namespace std;
void make(int len, char *s1, char *s2, char *s) // s1为先序 s2为中序
{
int i;
if (len <= 0)
return; // return 必不可少 否则死循环
else
{
for (i = 0; i < len; i++)
{
if (s1[0] == s2[i]) // 在中序中搜索根节点 实现递归
break;
}
}
// 关键部分
make(i, s1 + 1, s2, s); // 搜索上次搜索左侧部分
make(len - i - 1, s1 + i + 1, s2 + i + 1, s + i); // 搜索上次搜索右侧部分
s[len - 1] = s1[0]; // 后序输出 把递归找出的根节点从后存入 也就是打印当前根
}
int main()
{
char s1[100], s2[100], s[100];
scanf("%s %s", s1, s2);
int len = strlen(s1);
// s[len] = '\0'; // 不要忘记封口
make(len, s1, s2, s);
s[len] = '\0'; // 不要忘记封口
cout << s << endl;
return 0;
}