假設輸入的前序遍歷和中序遍歷的結果中都不含重複數字。
例如:輸入前序遍歷序列{1,2,4,7,3,5,6,8},和中序遍歷序列{4,7,2,1,5,3,8,6}
要求重建出該二叉樹,並輸出其頭結點。
二叉樹結點的定義如下:
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
}
思路分析:首先清楚這幾種遍歷的順序,前序遍歷:根左右;中序遍歷:左根右;即前序遍歷序列的第一個結點總是根結點。中序遍歷的根節點在中間,且根節點左側序列是左子樹的結點值,右側序列是右子樹的結點值。
所以首要任務是;找出根結點的值以及左子樹結點的值和右子樹結點的值。然後用遞歸的方法去完成。
c++代碼實現:
BinaryTreeNode* Construct(int* preorder,int* inorder,int length)
{
if(preorder == Null||inorder==Null||length<=0)
{
return Null;
}
return ConstructCore(preorder,preorder+length-1,inorder,inorder+length-1);
}
BinaryTreeNode* ConstructCore
(
int* startPreorder,int* endPreorder,int* startInorder,int* endInorder
)
{
//1.前序遍歷的第一個數字是根結點的值。以此根結點來創建新的二叉樹,只有根結點,左右子樹爲空。
int rootValue = startPreorder[0];
BinaryTreeNode* root = new BinaryTreeNode();
root->m_nValue=rootValue;
root->m_pLeft=root->m_pRight=Null;
if(startPreorder ==endPreorder)
{
if(startInorder == endInorder && *startPreorder == *startInorder)
return root;
else
throw std::exception("Invalid input.");
}
//2.在中序遍歷中找到根結點的值,在遍歷序列中劃分出左、右子樹對應的子序列。
int* rootInodrer = startInorder;
while(rootInodrer<=endInorder && *rootInodrer!=rootValue)
{
++rootInodrer;//找到根結點在中序遍歷中的位置
}
if(rootInodrer == endInorder && *rootInodrer!=rootValue)
{
throw std::exception("Invalid input.");
}
int leftLength = rootInodrer - startInorder;
int* leftPreorderEnd = startPreorder+leftLength;
//把構建二叉樹的大問題分解成構建左右子樹的兩個小問題。用遞歸的方式來解決。
if(leftLength>0)//3.構建左子樹
{
//新的左子樹的前序遍歷序列從(startPreorder+1)到(leftPreorderEnd)結束。實現了在遍歷序列中對左右子樹的劃分。
//新左子樹的中序遍歷序列從(startInorder)到(rootInodrer-1)結束。故可以用遞歸的方法來實現左子樹的創建。
root->m_pLeft = ConstructCore(startPreorder+1,leftPreorderEnd,startInorder,rootInodrer-1);//遞歸調用來分別構建左右子樹
}
if(leftLength<endPreorder-startPreorder)//4.構建右子樹
{
//新的右子樹的前序遍歷序列從(leftPreorderEnd+1)到(endPreorder)結束。
//新左子樹的中序遍歷序列從(rootInodrer+1)到(endInorder)結束。故可以用遞歸的方法來實現右子樹的創建。
root->m_pRight = ConstructCore(leftPreorderEnd+1,endPreorder,rootInodrer+1,endInorder);
}
return root;
}