一,美国血统
题目描述
农夫约翰非常认真地对待他的奶牛们的血统。然而他不是一个真正优秀的记帐员。他把他的奶牛 们的家谱作成二叉树,并且把二叉树以更线性的“树的中序遍历”和“树的前序遍历”的符号加以记录而 不是用图形的方法。
你的任务是在被给予奶牛家谱的“树中序遍历”和“树前序遍历”的符号后,创建奶牛家谱的“树的 后序遍历”的符号。每一头奶牛的姓名被译为一个唯一的字母。(你可能已经知道你可以在知道树的两 种遍历以后可以经常地重建这棵树。)显然,这里的树不会有多于 26 个的顶点。 这是在样例输入和 样例输出中的树的图形表达方式:
C
/ \
/ \
B G
/ \ /
A D H
/ \
E F
树的中序遍历是按照左子树,根,右子树的顺序访问节点。
树的前序遍历是按照根,左子树,右子树的顺序访问节点。
树的后序遍历是按照左子树,右子树,根的顺序访问节点。
输入格式
第一行: 树的中序遍历
第二行: 同样的树的前序遍历
输出格式
单独的一行表示该树的后序遍历。
输入输出样例
输入 #1复制
ABEDFCHG CBADEFGH
输出 #1复制
AEFDBHGC
分析:
1,这个题目其实和昨天的那个求前序排列差不多,思路是差不多的。
2,此题给出了中序和前序,求后序,前序是根左右,中序是左根右,后序是左右根。
3,我们根据前序找到根,然后根据找到的根,在中序中找到根所在的位置,然后将中序以根为界限分为两部分,再根据中序分为的两部分,将前序也分为两部分,这两部分就是左子树和右子树。
4,我们先遍历左子树找根,再遍历右子树找根,重复上面的步骤,为什么是先左后右呢?因为后序的顺序是左右根,我们每一次找到的根都是放在最后,等左右子树找完之后才输出根,所以每次找到的根都放在它找完左右子树后输出。
5,需要注意的是,当我要找的子树已经找完了的时候就返回,结束此次递归,如果一直找,就会陷入死循环。
代码如下:
c++
#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);
string rightpre=pre.substr(k);
string leftinor=inor.substr(0,k);
string rightinor=inor.substr(k+1);
//cout<<"ff "<<leftinor<<" "<<rightinor<<" "<<leftpre<<" "<<rightpre<<endl;
work(leftpre,leftinor);
work(rightpre,rightinor);
printf("%c\n",root);
}
int main()
{
cin>>inor>>pre;
work(pre,inor);
return 0;
}
c语言
#include<stdio.h>
#include<string.h>
void tree(char z[26],char q[26])
{
char c=q[0];
char lz[26]={0},rz[26]={0},lq[26]={0},rq[26]={0};
int k;
if(strlen(q)==0)
return;
for(int i=0;i<strlen(z);i++)
if(z[i]==c)
{
k=i;
break;
}
for(int i=0;i<k;i++)
lz[i]=z[i];
int f=0;
for(int i=k+1;i<strlen(z);i++)
rz[f++]=z[i];
for(int i=1;i<=k;i++)
lq[i-1]=q[i];
f=0;
for(int i=k+1;i<strlen(q);i++)
rq[f++]=q[i];
//printf("ff %s %s %s %s\n",lz,rz,lq,rq);
tree(lz,lq);
tree(rz,rq);
printf("%c",c);
}
int main()
{
char z[26],q[26];
scanf("%s%*c%s",z,q);
tree(z,q);
}
二,新二叉树
## 题目描述
输入一串二叉树,输出其前序遍历。
## 输入格式
第一行为二叉树的节点数 $n$。($1 \leq n \leq 26$)
后面 $n$ 行,每一个字母为节点,后两个字母分别为其左右儿子。特别地,数据保证第一行读入的节点必为根节点。
空节点用 `*` 表示
## 输出格式
二叉树的前序遍历。
## 样例 #1
### 样例输入 #1
```
6
abc
bdi
cj*
d**
i**
j**
```
### 样例输出 #1
abdicj
分析:
1,前序是根左右,所以我们先找根,找到根之后就找左子树和右子树。
2,输入的数据,我们默认第一组数据的第一个字母就是根节点,所以第一个根节点我们直接输出就行,然后我们要找左子树和右子树的第一个值,也就是接下来的子树的根节点。
3,什么时候退出呢?那就是当子树已经完结也就是接下来没有子树的时候,就退出,就不用找了。
4,一定要注意内存的问题,我的内存就一直报错。
代码如下:
c++
#include<bits/stdc++.h>
using namespace std;
int n;
struct node{
char lc,rc;
};
node tree[10001];
void dfs(char x)
{
if(x=='*') return;
cout<<x;
dfs(tree[x].lc);
dfs(tree[x].rc);
}
int main()
{
cin>>n;
char h1;
cin>>h1;
cin>>tree[h1].lc>>tree[h1].rc;
for(int i=2;i<=n;i++){
char h;
cin>>h;
cin>>tree[h].lc>>tree[h].rc;
}
dfs(h1);
}
c语言
#include<stdio.h>
#include<math.h>
#include<string.h>
char h,h1;
struct kk
{
char l;
char r;
}jd[200];
void ss(char head)
{
if(head=='*')
return;
printf("%c",head);
ss(jd[head].l);
ss(jd[head].r);
}
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf(" %c",&h1);
scanf("%c%c",&jd[h1].l,&jd[h1].r);
if(i==0)
h=h1;
}
ss(h);
}
总结:
1,今天重新复习了二叉树,二叉树的遍历的话,主要就是分为前序,中序,后序。
2,前序为根左右,中序为左根右,后序为左右根,一个巧记的点在于什么序那么根的位置就在什么地方。
3,一般的话,求序列使用的是递归,递归的特性很好求序列。
4,一般在求序列的时候是先找的根,再根据根找左右子树。