題目:輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。
例如:輸入前序遍歷 {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~*/