LG-二叉树-P-1827

题目相关

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

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

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

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

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

输入格式
第一行: 树的中序遍历
第二行: 同样的树的前序遍历

输出格式
单独的一行表示该树的后序遍历。

输入输出样例
输入
ABEDFCHG
CBADEFGH
输出
AEFDBHGC

题解相关

自己的

思路

首先分析题目,题目简单来看就是根据二叉树的先序和中序(来确定二叉树)输出后序。根据三种遍历的特点我们可以:

  1. 因为先序最方便找到的也是第一个字符,就是根,而中序可以通过根来分割左子树和右子树,我们可以简单地构思出一个DFS的函数。
  2. 先序找到根,中序找到该根的左右子树,dfs先进右子树,找到根,左右子树……后进左子树,找到根,左右子树……最后只剩根输入。
  3. 因为后序左右根的特征,所以要将我们先前输入的顺序整个颠倒过来,最后输出即可。

问题

  1. 递归结束条件?答:进入函数的字符串为空串
  2. 进入递归的条件?答:进入左右子树的DFS时要先判断该根是否有左右子树,无的话就会发生越界等不可预知的情况!
  3. 如何颠倒?答:算法库里的reverse函数。

别人的

字符串切割时应注意的问题
那便是切割位置。STL的string类型自带切割方法substr,但搞不清参数就会导致WA甚至RE。

首先我们搞清楚substr方法的使用方法。
string s;
s.substr(order,k);
参数传入一个order,一个k。
函数将会从下标为order的位置开始,连续截取k个字符。返回截取后的字符串。
order显然不能超出0~s.size()-1的范围。
但是,如果order+k超过了s.size()-1,函数会自动只截取到s的末尾。
如果不传入k,那么默认截取到末尾。
这个函数是返回一个字符串,而不是对s进行改动。

s.find ( c );
//在字符串s中查找第一个字符c的位置,返回下标,如果没有返回string::npos

s.erase(it);
//在字符串中删除指针it所指向的字符

s.begin();
//返回s的首字符的指针(迭代器)

代码

自己的

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
string pre, in, post;
void PostAH(string pre, string in){
	if(pre.size()>1){
		char ch=pre[0];
		post+=ch;
		int i=in.find(ch);//根在中序的位置 
		//int l=in.substr(0,i).size();//左子树长度 //l不就等于i吗…… 
		if(i!=in.size()-1) //有右子树 
			PostAH(pre.substr(i+1), in.substr(i+1));//右子树 
		if(i!=0)//有左子树 
			PostAH(pre.substr(1,i), in.substr(0,i));//左子树 
	}
	else if(pre.size()==1) post+=pre;
}
int main()
{
	cin>>in;
	cin>>pre;
	PostAH(pre, in);
	reverse(post.begin(), post.end());
	cout<<post;
	return 0;
}

别人的

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值