题目链接:http://poj.org/problem?id=2255
题目大意:
题目中给出一个二叉树的前序遍历和中序遍历,输出这个二叉树的后序遍历。二叉树中的结点是大写英文字母,最多有26个结点。
解题思路:
这道题涉及到一种重要的数据结构——二叉树,题目很简单,但是考查了对二叉树的遍历的理解。二叉树,顾名思义,就是每一个结点都有两个子结点的树。二叉树的遍历主要有四种:前序遍历、中序遍历、后序遍历和层序遍历。前三种都是使用栈来实现遍历,只是访问结点的顺序不同(有点像深搜),而层序遍历是使用队列来实现遍历(有点像广搜)。
前序遍历:先访问根结点,再遍历左子树,后遍历右子树;
中序遍历:先遍历左子树,再访问根结点,后遍历右子树;
后序遍历:先遍历左子树,在遍历右子树,后访问根结点。
例如:
二叉树:
前序遍历:ABDECFG;
在前序遍历中,先访问结点,然后访问左子树上遇到的每一个结点,继续这个过程,直到一个结点的左结点是空节点。这时,返回到最近的有右子树的父亲结点,并从该结点的右子树继续遍历。代码:
void preorder(tree_pointer ptr)
{
if (ptr) {
printf("%d",ptr -> data);
preorder(ptr -> left_child);
preorder(ptr -> right_child);
}
}
中序遍历:DBEAFCG;
中序遍历就是从二叉树的根结点开始,向树的左子树移动,直到遇到空结点为止,然后访问空结点的父亲结点,接着继续遍历这个结点的右子树。如果右子树没有子结点可以遍历,那么就继续遍历上一层最后一个未被访问的结点。代码:
void preorder(tree_pointer ptr)
{
if (ptr) {
preorder(ptr -> left_child);
printf("%d",ptr -> data);
preorder(ptr -> right_child);
}
}
后序遍历:DEBFGCA;
在后序遍历中,先遍历结点的左右子树,然后才对该结点进行访问。代码:
void postorder(tree_pointer ptr)
{
if (ptr) {
postorder(ptr -> left_child);
postorder(ptr -> right_child);
printf("%d",ptr -> data);
}
}
在这道题中,题目给出了二叉树的前序遍历和中序遍历。从前序遍历我们可以知道根结点,从中序遍历我们可以知道某个结点的左右子树。所以先递归左子树,再递归右子树,最后输出根结点。这个顺序就是后序遍历的顺序。
例如:图中的二叉树,中序遍历是:DBEAFCG,前序遍历是:ABDECFG。由前序遍历我们可以知道二叉树的根结点是A。所以在中序遍历中:可以得到DBE是A结点的左子树,FCG是A结点的右子树。所以继续遍历左子树,即:。这时,由前序遍历我们可以知道B是子树DBE的根结点,所以继续遍历左子树,即:。此时,D结点既没有左子树,也没有右子树,将D结点输出。不断继续这个过程,直到输出所有结点。
代码:
/*
ID: Code-Cola
PROG: 2255
LANG: C++
*/
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
/********** 全局变量 **********/
string s_preorder, s_inorder; //字符串类存储前序遍历和中序遍历
/********** 函数声明 **********/
void postorder(int first, int last, int root); //递归遍历
int main()
{
int i;
while (cin >> s_preorder >> s_inorder) {
postorder(0,s_inorder.size() - 1, 0); //从字符串的左右位置开始遍历
cout << endl;
}
return 0;
}
void postorder(int first, int last, int root)
{
if (first <= last) {
postorder(first, s_inorder.find(s_preorder[root]) - 1, root + 1);//遍历左子树 注意左右位置
postorder(s_inorder.find(s_preorder[root]) + 1, last, root + 1); //遍历右子树
cout << s_preorder[root]; //输出结点
s_preorder.erase(root,1); //删除已输出的结点
}
}