w9_01

题目

# 美国血统

## 题目描述

农夫约翰非常认真地对待他的奶牛们的血统。然而他不是一个真正优秀的记帐员。他把他的奶牛 们的家谱作成二叉树,并且把二叉树以更线性的“树的中序遍历”和“树的前序遍历”的符号加以记录而 不是用图形的方法。

你的任务是在被给予奶牛家谱的“树中序遍历”和“树前序遍历”的符号后,创建奶牛家谱的“树的 后序遍历”的符号。每一头奶牛的姓名被译为一个唯一的字母。(你可能已经知道你可以在知道树的两 种遍历以后可以经常地重建这棵树。)显然,这里的树不会有多于 26 个的顶点。 这是在样例输入和 样例输出中的树的图形表达方式:


```

         C
         /  \
        /  \
       B    G
      / \  /
       A   D  H
        / \
       E   F

```

树的中序遍历是按照左子树,根,右子树的顺序访问节点。

树的前序遍历是按照根,左子树,右子树的顺序访问节点。

树的后序遍历是按照左子树,右子树,根的顺序访问节点。

## 输入格式

第一行: 树的中序遍历

第二行: 同样的树的前序遍历

## 输出格式

单独的一行表示该树的后序遍历。

## 样例 #1

### 样例输入 #1

```
ABEDFCHG
CBADEFGH
```

### 样例输出 #1

```
AEFDBHGC
```

 

解题思路:

前序遍历是先遍历根节点,再遍历根节点的左右子树,所以前序序列的第一个节点,一定是根节点。找到根节点,再确定根节点在中序序列中的位置,

就可以分出左右两棵子树,通过递归不断切割字符串就好了。

根据题目中的例题,可以分析:看到前序序列的第一个字符是 C ,那么根节点就是 C ,找到中序中对应的位置,数下标,发现 C 在 5 处 (注意字符串下标从0开始)令k=5,设在中序序列中根节点的位置是k。

然后在先序序列中把C删掉。

中序序列中C在5处,那么左右子树分别就是ABEDF(0~4)和HG(6~7)。

很容易发现:中序序列中左子树就是从0开始切割到k-1,也就是切割了k个字符;中序序列中右子树就是从k+1开始,一直切割到最后。

然后找前序序列切割的规律。

中序序列中左子树是ABEDF,右子树是HG,对应在前序序列中就是BADEF(0~4)和GH(5~6)。

那么前序序列中左子树是从0开始切割到k-1,也就是切割了k个字符;前序序列中右子树就是从k开始,一直切割到最后。

具体代码如下:

#include<string>
#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;
string pre,inor;
void work(string pre,string inor)
{
if(pre.empty())return;
//如果序列空了,就没必要继续了
char root=pre[0];
//取到前序序列的首字母,即根节点
int k=inor.find(root);
//找到中序序列中根节点的位置
pre.erase(pre.begin());
//删去前序序列中的根节点
string leftpre=pre.substr(0,k);
//从0开始切割k个
string rightpre=pre.substr(k);
//从k开始切割到最后
string leftinor=inor.substr(0,k);
//从0开始切割k个
string rightinor=inor.substr(k+1);
//从k+1开始切割到最后
work(leftpre,leftinor);
work(rightpre,rightinor);
printf("%c",root);
//因为要输出后序序列,所以是左右根
//先遍历左子树,再右子树,再根节点
}
int main()
{
cin>>inor>>pre;
work(pre,inor);
putchar('\n');
return 0;
}

posted @ 2023-05-10 12:50  冉思银  阅读(11)  评论(0)    收藏  举报