【7004】二叉树的遍历问题

Time Limit: 10 second
Memory Limit: 2 MB

问题描述
输入一棵二叉树的先序和中序遍历序列,输出其后序遍历序列。

Input

输入文件共两行,第一行一个字符串,表示树的先序遍历,第二行一个字符串,表示树的中序遍历。树的结点一律用小写字母表示。

Output

输出文件仅一行,表示树的后序遍历的序列。 

Sample Input

abdec
dbeac

Sample Output

debca

【题解】

先序遍历。
是先输出当前访问到的节点。
然后访问左儿子。然后访问右儿子。
这也就是说先序遍历的第一个节点肯定是根节点。


然后中序遍历。是先访问左儿子。然后输出访问的节点。然后输出右儿子。
我们可以先根据先序遍历。找到这个树的根节点。
假设根节点root在中序遍历中的位置为pos.
则1..pos-1为根的左子树。
pos+1..max为根的右子树。


然后1..pos-1这个左子树。它的根节点是什么呢?
当然就是先序遍历的第二个节点。
因为先序遍历是先访问了根节点。且先输出根节点。
然后访问根节点的左子树。当然第一个访问的是左子树的根节点。然后输出这个左子树的根节点。然后。。
对!就在第二个节点。它就是我们需要的左子树的根节点。
然后我们依然用中序遍历。找到这个<左子树的根节点>的左子树和右子树。
依次类推。根节点的左子树的左子树的根节点为先序遍历的第3个节点..
这些子树可以用区间先表示出来。
如果区间的大小{上限减去下限为1}则这个节点为最下面一层的节点。叶子节点。那么就不要继续操作了。
然后每层递归(什么?你还看不出来这里要用递归??)都要返回当前这段区间的根节点。给这个根节点
的爸爸。
然后根据得到的l[]和r[]数组(表示某个节点的左儿子和右儿子)。从根节点开始进行后序遍历。
(后序遍历:先访问左儿子。后访问右儿子。最后输出当前访问的这个节点);

【代码】

#include <cstdio>
#include <iostream>
#include <string>

using namespace std;

string s1, s2;
int tot,ll[29],rr[29],root;
int xianxu[29], zhongxu[29];
int now = 1;

void input_data() //输入有这么多行。是为了在字符串前面加一个空格。
{ //因为C++的字符串从0开始计数。有点不习惯。然后把字母转换成相应的数字。a-z对应1..26
	string temp;
	getline(cin, temp);
	s1 = " ";
	s1 += temp;
	getline(cin, temp);
	s2 = " ";
	s2 += temp;
	for (int i = 1; i <= s1.size() - 1; i++) //字符转数字。
		xianxu[i] = s1[i] - 'a' + 1;
	xianxu[0] = s1.size() - 1;
	for (int i = 1; i <= s2.size() - 1; i++)
		zhongxu[i] = s2[i] - 'a' + 1;
	zhongxu[0] = s2.size() - 1;
}

int sear_ch(int l, int r) //返回l..r这段区间的根节点。
{
	if (r < l) //如果出现右界小于左界的情况。则返回0.表示这个节点不存在。
		return 0;
	if (l == r)//如果左界和右界相同。则说明这里只有一个节点。则返回这个节点。
		return xianxu[now++];//我们要靠先序来判断l..r这个子树的根节点
	else//对于只有一个元素来说。我们认为这个xianxu[now]是一个根节点。
	{
		int pp;
		int key2 = xianxu[now];//这是l..r这个子树的根节点
		for (int i = l; i <= r; i++)//找到根节点在中序中的位置pp
			if (zhongxu[i] == key2) //中序遍历中L..pp-1,和pp+1.。R分别为key2的左子树和右子树。
			{
				pp = i;
				break;
			}
		now++;//寻找先序遍历中出现的下一个元素即该根节点key2的左子树的根节点。
		ll[key2] = sear_ch(l, pp - 1); //注意我们每一段区间的根节点都有记录下来(key2)。然后返回即可。
		rr[key2] = sear_ch(pp + 1, r); //先序是先访问完左子树再访问右子树的。要遵循其规律。
		return key2;//返回l..r这个区间的根节点。
	}
}

void output_ans(int t) //这是后序遍历一棵树的递归程序。
{
	if (ll[t] != 0)
		output_ans(ll[t]);
	if (rr[t] != 0)
		output_ans(rr[t]);
	char aa = t + 'a' - 1;//要输出的是字母;
	putchar(aa);//输出单个字符。
}

void get_ans()
{
	int root = xianxu[now];//先找到整棵树的根节点。
	int pos = 0;
	for (int i = 1;i <= zhongxu[0];i++) //找到其在中序遍历中的位置
		if (zhongxu[i] == root)
		{
			pos = i;
			break;
		}
	now++;//接下来xianxu[now]指向根节点的左子树的根节点。
	ll[root] = sear_ch(1, pos - 1);//这是其左子树 sear_ch(l,r)函数会返回l..r这段区间的根节点。
	rr[root] = sear_ch(pos + 1, xianxu[0]);//这是其右子树。
	output_ans(root);
}

int main()
{
	input_data();
	get_ans();
	return 0;
}


原文地址:https://www.cnblogs.com/AWCXV/p/7632309.html