二叉树是数据结构中十分重要的一种树。通常我们定义是:
struct Node
{
Node * lchild;
Node * rchild;
char c;
}Tree[50];
还有就是二叉树的前序遍历,中序遍历和后序遍历也是十分重要。接下来看一个例题:
题目描述:
二叉树的前序、中序、后序遍历的定义:
前序遍历:对任一子树,先访问跟,然后遍历其左子树,最后遍历其右子树;
中序遍历:对任一子树,先遍历其左子树,然后访问根,最后遍历其右子树;
后序遍历:对任一子树,先遍历其左子树,然后遍历其右子树,最后访问根。
给定一棵二叉树的前序遍历和中序遍历,求其后序遍历(提示:给定前序遍历与中序遍历能够唯一确定后序遍历)。
输入:
两个字符串,其长度n均小于等于26。
第一行为前序遍历,第二行为中序遍历。
二叉树中的结点名称以大写字母表示:A,B,C....最多26个结点。
输出:
输入样例可能有多组,对于每组测试样例,
输出一行,为后序遍历的字符串。
样例
输入:
ABC
BAC
FDXEAG
XDEFAG
样例输出:
BCA
XEDGAF
来源:
2006年清华大学计算机研究生机试真题
代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct Node
{
Node * lchild;
Node * rchild;
char c;
}Tree[50];
int loc ; //静态数组中已经分配的节点个数
Node * creat()
{
Tree[loc].lchild = Tree[loc].rchild = NULL;
return &Tree[loc++];
}
char str1[30], str2[30]; //保存前序和中序遍历字符串
//后序遍历
void postOrder(Node * T)
{
if(T->lchild != NULL)
{
postOrder(T->lchild);
}
if(T->rchild != NULL)
{
postOrder(T->rchild);
}
printf("%c ",T->c);
}
//由字符串的前序遍历和中序遍历还原树,并返回其根节点。
Node * build(int s1, int e1, int s2, int e2)
{
Node * ret = creat();
ret->c = str1[s1];
int rootIdx;
for(int i=s2; i<=e2; i++)
{
if(str2[i] == str1[s1])
{
rootIdx = i;
break;
}
}
if(rootIdx != s2) //若左子树不为空
{
ret->lchild = build(s1+1, s1+(rootIdx-s2), s2, rootIdx-1);
}
if(rootIdx != e2)
{
ret->rchild = build(s1+(rootIdx-s2)+1, e1, rootIdx+1, e2);
}
return ret;
}
int main()
{
while(scanf_s("%s", str1, 10)!=EOF)
{
scanf_s("%s",str2,10);
loc = 0;
int L1 = strlen(str1);
int L2 = strlen(str2);
Node * T = build(0, L1-1, 0, L2-1);
postOrder(T);
printf("\n");
}
return 0;
}
这个代码是书上的代码,其中最核心也最难搞懂的就是build函数。其实最核心的在于这四个参数,其中s1和e1代表的是每次前序遍历的起点和终点,s2和e2代表的是每次中序遍历的起点和终点。就是每次遍历都有一个范围,想想根据前序遍历和中序遍历求后序遍历的算法,其实每次我们都会根据当前的根节点将树划分为左右子树。