一、題目:輸入某二叉樹的前序遍歷和中序遍歷的結果,重建出該二叉樹,假設無重複數字。例如前序遍歷結果爲{1,2,4,7,3,5,6,8},中序遍歷結果爲{4,7,2,1,5,3,8,6},重建出該二叉樹並輸出其頭節點。
首先看到該題目,我們心裏應該清楚二叉樹的前序遍歷和中序遍歷各自有什麼特點,想不通的話可以在紙上畫一畫。前序遍歷序列中第一個數字總是該二叉樹的根節點,但是在中序遍歷序列中根節點在中間,結合兩個序列,我們很容易就能知道二叉樹的根節點以及左右子樹,如下圖所示:
依照這種方法,第二遍查找根節點爲2,那麼在左子樹中(中序遍歷序列)可以發現2只有左子樹,接着根節點爲4時,右子樹是7......按照這種思路就可以將一棵完整的二叉樹重構出來了,不難發現,這裏用了一種遞歸的思路,重建的二叉樹如下所示:建議在紙上畫一畫
在瞭解整棵樹如何重構之後,算法代碼也就很容易能夠寫出來了,就是遞歸方法的一種實現
二叉樹節點定義:
struct BinaryTreeNode
{
int value;
BinaryTreeNode* pLeft; //左節點
BinaryTreeNode* pRight; //右節點
};
遞歸代碼如下:
BinaryTreeNode* RebuildCore(int *startPreorder,int *endPreorder,int *startInorder,int *endInorder)
{
int rootValue = startPreorder[0];
BinaryTreeNode* root =new BinaryTreeNode();
root->value = rootValue;
root->pLeft = root->pRight = NULL;
//判斷前序和中序遍歷中是不是隻有一個節點,若是則該樹就只有一個節點即根
if(startPreorder == endPreorder)
{
if(startInorder == endInorder && *startPreorder == *startInorder)
{
return root;
}
else
{
throw std::exception("invailed input");
}
}
//在中序遍歷中找到根節點
int *rootInorder = startInorder;
while (rootInorder <= endInorder && *rootInorder != rootValue)
{
rootInorder++;
}
if (rootInorder == endInorder && *rootInorder != rootValue)
{
throw std::exception("invailed input");
}
int leftLength = rootInorder - startInorder;
int *leftInorderNow = startPreorder + leftLength;
//構建左子樹
if(leftLength > 0)
{
root->pLeft = RebuildCore(startPreorder+1,leftInorderNow,startInorder,rootInorder-1);
}
//構建右子樹
if(leftLength < endPreorder - startPreorder)
{
root->pRight = RebuildCore(leftInorderNow+1,endPreorder,rootInorder+1,endInorder);
}
return root;
}
BinaryTreeNode* Rebuild(int *preorder,int *inorder,int length)
{
if (preorder == NULL || inorder == NULL || length < 0)
{
return NULL;
}
return RebuildCore(preorder,preorder+length-1,inorder,inorder+length-1);
}
參考劍指offer上的面試題,以上就是大概的思路,感受最深的是在寫代碼之前一定要先整理好自己的思路,不要一上來就開始寫,就想着我要實現這個功能,先把思路整理好,代碼實現就是將自己的思路用另外一種語言呈現出來罷了,所以,思路很重要。沒有思路的話,在紙上畫一畫,想一想,這個問題還能不能拆分成一些更小的自己能夠解決的一些問題,然後再整合,解決一個大問題。