给定一棵二叉树的前序遍历和中序遍历,求其后序遍历(提示:给定前序遍历与中序遍历能够唯一确定后序遍历)。
输入描述:
两个字符串,其长度n均小于等于26。
第一行为前序遍历,第二行为中序遍历。
二叉树中的结点名称以大写字母表示:A,B,C....最多26个结点。
输出描述:
输入样例可能有多组,对于每组测试样例,
输出一行,为后序遍历的字符串。
如:
输入:
ABC
BAC
FDXEAG
XDEFAG
输出:
BCA
XEDGAF
思路:先序+中序求后序,先序的第一个字符是根root,所以得在中序序列中遍历找出root所在位置,设由中序第一位向前挪i次后找到root,将中序一分为二,root的左子树和右子树,则相应的,前序中也可划分出左子树和右子树,只是现在只知道前序和中序的首地址,所以再加上长度len和挪动的次数就可以在前序,中序中分离出左和右。
#include <iostream>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
typedef struct Tnode{
char ch;
Tnode *lc;
Tnode *rc;
}Tnode;
Tnode *Create_Tree(Tnode *T,char *pre,char *in,int len){
T=(Tnode*)malloc(sizeof(Tnode));
T->lc=T->rc=NULL;//初始化节点,无值;
if(len<=0){//若剩余长度<=0,停止;否则继续遍历查找
T=NULL;
}
else{
int i=0;
while(*(pre)!=*(in+i)&&i<=len){//这里使用指针类型更方便,找出root在中序序列中的位置
i++;
}
T->ch=*pre;
T->lc=Create_Tree(T->lc,pre+1,in,i);/*这里preoder+1是指前序序列中的首元素已经确定位置了,所以前序序列需向前移动一位,而中序序列还是in是因为它没法指定自己的区间,但是有了长度i就可以了,区间是从0---i-1;所以此处无论是pre 还是in ,都是指向自己的起始地址,借助i可以知道截止地址在哪; */
T->rc=Create_Tree(T->rc,pre+1+i,in+i+1,len-1-i);
}
return T;
}
void PostPrint(Tnode *T){
if(T){
PostPrint(T->lc);
PostPrint(T->rc);
cout<<T->ch;
}
}
int main()
{
char pre[27],in[27];
while(cin>>pre){
cin>>in;
Tnode *T=NULL;
int len=strlen(pre);
T=Create_Tree(T,pre,in,len);
PostPrint(T);
cout<<endl;
}
return 0;
}
NOTE:
难点:递归解决该问题:首先在前序序列中找根root,即前序序列第一个字母,然后在中序序列中找对应的字母,此时root将中序序列分为左根右三部分,保存root,再在左子树中递归,在右子树中递归,直到树的长度小于等于0;所以需要有一个长度变量,不仅提示是否退出递归,而且也容易区分左右子树的遍历区间;
1.由前序和中序序列重新建树时,忘了要写递归截止条件,即当长度<=0时退出递归;
2. char*和char[]的区别----前者表示元素char *ch; (ch)表示第一个字符
3. 主函数中定义前序序列preorder[],中序序列inorder[]为char型数组,直接分配空间,而不是char型;