題目鏈接: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); //刪除已輸出的結點
}
}