题目描述
二叉树的前序、中序、后序遍历的定义: 前序遍历:对任一子树,先访问跟,然后遍历其左子树,最后遍历其右子树; 中序遍历:对任一子树,先遍历其左子树,然后访问根,最后遍历其右子树; 后序遍历:对任一子树,先遍历其左子树,然后遍历其右子树,最后访问根。 给定一棵二叉树的前序遍历和中序遍历,求其后序遍历(提示:给定前序遍历与中序遍历能够唯一确定后序遍历)。
输入描述:
两个字符串,其长度n均小于等于26。 第一行为前序遍历,第二行为中序遍历。 二叉树中的结点名称以大写字母表示:A,B,C....最多26个结点。
输出描述:
输入样例可能有多组,对于每组测试样例, 输出一行,为后序遍历的字符串。
示例1
输入
ABC BAC FDXEAG XDEFAG
输出
BCA XEDGAF
这道题的结局思路(我觉得)采用了分治的策略。
已知二叉树的前序序列和中序序列,求后序序列。对于一串前序序列,可知第一个结点是根节点,那么将该结点放置在后序序列的最后。
然后在中序序列里寻找该根结点的位置k,那么k之前的序列即为左孩子,k之后的即为右孩子,并且可以求得左右孩子的长度,也就知道了在前序序列里左右孩子的位置。
对左右孩子依旧采取这种策略,直到后序序列被填满,即可得到后序序列。
在求后序序列时是递归求解,其终结递归条件需要注意。一开始我以为是前序序列首位置等于前序序列末位置时即停止。后来发现不对,如果一个序列没有左孩子,那么放置根节点后,其左孩子长度为0,新的前序序列首位置加1,末位置不变,导致首位置直接大于末位置。
所以终结递归条件应是,如果首位置大于末位置即停止。
代码:
#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;
string pre;
string in;
char post[26];
/*
* low_pre 表示前序序列首位置
* high_pre 表示前序序列末位置
* 其余类似
*/
void postSearch(int low_pre,int high_pre,int low_in, int high_in,int low_post,int high_post)
{
if(low_pre > high_pre)
return ;
char c = pre[low_pre];
post[high_post] = c; //把先序序列第一个字符(也就是树根)赋值给后序序列的最后一个位置
int k=0;
while(in[low_in+k] != c ) //寻找先序序列树根在中序序列中的位置
k++; // 由此可以知道,该位置前面的序列是树根的左孩子,后面是树根的右孩子
// 可以知道 左孩子的长度为k,把整个序列分成两部分
//此时后序序列为 (low_post,low_post+k-1) (low_post+k,high_post-1)
//中序序列 (low_in,low_in+k-1),(low_in+k+1,high_in)
//前序序列变成了 (low_pre+1,low_pre+k),(low_pre+k+1,high_pre)
postSearch(low_pre+1,low_pre+k,low_in,low_in+k-1,low_post,low_post+k-1);
postSearch(low_pre+k+1,high_pre,low_in+k+1,high_in,low_post+k,high_post-1);
}
int main()
{
while(cin>>pre)
{
int i;
cin>>in;
int length = pre.size();
postSearch(0,length-1,0,length-1,0,length-1);
printf("%s",post);
cout<<endl;
}
return 0;
}