劍指offer_面試題6_重建二叉樹(分解步驟,逐個擊破)

題目:輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。

例如:輸入前序遍歷 {1,2,4,7,3,5,6,8} 和中序遍歷序列 {4,7,2,1,5,3,8,6},則重建出圖2.6所示的二叉樹並輸出它的頭結點。       

感觸:複雜問題,要將它分解成一個個小問題,逐個擊破,從而解決大問題。

我們都知道一個概念,知道 前序遍歷 和 中序遍歷,可以唯一確定一顆二叉樹。

因此,我們首先需要如何根據這兩個已知條件,來畫出這顆二叉樹。在解決這道題的時候,最好用紙和筆,自己先實現一遍,然後分析自己實現的過程,分解每一個步驟,而問題的算法就是根據你解決問題的步驟而來

我在做的過程中,曾參考書中代碼,然而別人的代碼終究不是自己的,是別人的思路,自己在理解的過程中,總有這樣那樣的問題。因此,最好將書上的代碼放一邊,自己動手

去實踐。按照自己的思路來解決整個問題,這樣你在測試的時候,纔有針對性。當然對於書中代碼呈現的解決思路,需要選擇性吸收。

對於這個問題,我把它分成三步:

1、首先拿到前序遍歷序列,其作用就是用來取得 根節點。(需要理解,二叉樹是一個遞歸的過程,其子樹亦是一個二叉樹,每一次都是取得 二叉樹的根節點)

2、找到 “前序遍歷中取得的根節點”  在中序遍歷序列中的位置

3、找到該位置後,就可以確定 該根節點 所接的左右子樹(如下圖所示),然後對這 子 二叉樹進行遞歸操作。

這樣又從第一步開始了,依次取得每一棵子二叉樹的根節點。從而完成整棵樹的重建。

代碼如下:

在解決問題的過程中,經常出現考慮問題不全面的問題,比如 下面代碼中,加的一個函數 Judge_array(),它用來測試當你輸入的前序序列和中序序列 不匹配的情況。這一點一開始乜有考慮到。需要 銘記,警醒!

劍指offer中,有句話說的很好,“最好在寫代碼前,考慮好測試用例“。在擼代碼的過程中,特別有感觸。

/****************************************************************************/
/** 題目:輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。    */
/**       假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如    */
/**       輸入前序遍歷{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6}    */
/**       則重建出圖2.6所示的二叉樹並輸出它的頭結點。                    */
/** 時間:2015.7.25        作者:jwt                                       */
/****************************************************************************/
#include <iostream>

using namespace std;

typedef struct node {
    int value;
    struct node *lchild;
    struct node *rchild;
}BiTree_Node;

/**用於判斷前序遍歷序列和中序遍歷數列書否匹配*/
bool Judge_array(int *pre,int *in,int n)
{
    int i, j;
    int k = 0;
    for(i = 0; i < n; i++)
    {
        for(j = 0; j < n; j++)
        {
            if(pre[i] == in[j])
                k++;
        }
    }
    if(k != n)
        return false;
    else
        return true;
}

/*重建二叉樹的遞歸操作,對於這個問題,用指針更加方便 */
BiTree_Node *Construct(int *pre_start, int *in_start, int len)
{
    /**對於前序遍歷數列,只做一件事,取得根節點root */
    int root_value = pre_start[0];
    BiTree_Node *root;
    root = new BiTree_Node;
    root->value = root_value;
    root->lchild = NULL;
    root->rchild = NULL;

    /**在中序遍歷中尋找上面取得的root的位置*/
    int k = 0;
    int new_len;
    while(root_value != in_start[k] && k < len)
    {
        k++;
    }
    new_len = k;

    /**根據所找到的位置,判斷左右子樹*/
    if(new_len > 0)
    {
        root->lchild = Construct(pre_start+1, in_start, new_len);
        /*new_len 表示左子樹的長度*/
    }
    if(len - new_len - 1> 0)
    {
        root->rchild = Construct(pre_start+new_len+1, in_start+new_len+1, len-new_len-1);
        /*len-new_len-1 表示右子樹的長度*/
    }

    return root;
}

/*重建二叉樹函數*/
BiTree_Node *Construct_BiTree(int pre[],int in[],int length)
{
    if(pre == NULL || in == NULL || length <= 0 || !Judge_array(pre, in, length))
        return NULL;
    else
        return Construct(pre, in, length);
}

/**二叉樹後序遍歷,通過後序遍歷判斷重建的二叉樹是否正確*/
void Postorder(BiTree_Node *root)
{
    if(NULL == root)
        return;
    else{
        Postorder(root->lchild);
        Postorder(root->rchild);
        cout << root->value << ' ';
    }
}

int main()
{
    int pre[8] = {1,2,4,7,3,5,6,8};
    int in[8] = {4,7,2,1,5,3,8,6};

    //int pre[5] = {1,2,3,4,5};
    //int in[5] = {5,4,3,2,1};

    //int pre[6] = {1,2,3,6,7,8};
    //int in[6] = {3,2,1,6,7,8};

    //int pre[5] = {1,2,3,4,5};
    //int in[5] = {1,2,3,4,6};

    BiTree_Node *root = Construct_BiTree(pre,in,8);
    Postorder(root);
    return 0;
}

結果如下:(可以用主函數註釋部分,測試其他情況)

/*點滴積累,我的一小步O(∩_∩)O~*/

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