poj2255 Tree Recovery 二叉樹遍歷

題目鏈接: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。所以在中序遍歷中:可以得到DBEA結點的左子樹,FCGA結點的右子樹。所以繼續遍歷左子樹,即:。這時,由前序遍歷我們可以知道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);                                        //刪除已輸出的結點
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章