题目:输入某二叉树的前序遍历和中序遍历的结果, 请重建该二叉树。假设输入的前序遍历和中序遍历的结果汇总都不含有重复的数字。例如,输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建如下
1
/ \
2 3
/ / \
4 5 6
\ /
7 8 ,并输出它的头结点。二叉树的定义如下:
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};
分析:
前序遍历时:DLR 1 2 4 7 3 5 6 8
中序遍历时:LDR 4 7 2 1 5 3 8 6
前序遍历的第一个数字1结束根节点的值,所有根据中序的遍历结果可以确定1前面的数字为3个左子树的值
1后面的数字为4个右子树的值,所以以后的左右子树可以通过递归构建。
实现代码:
/*
参数:
startPreorder:前序遍历的数组
endPreorder:前序遍历的结束值
startInorder:中序遍历的数组
endInoder:中序遍历的结束值
*/
BinaryTreeNode* ConstrcuctCore(int *startPreorder, int *endPreorder, int* startInorder, int* endInorder)
{
//前序遍历的第一个数字是根节点的值
int rootValue = startInorder[0];
BinaryTreeNode* root = new BinaryTreeNode();
root->m_nValue = rootValue; //赋值给根节点
root->m_pLeft = root->m_pRight = nullptr; //根节点的左右子树初始化为空
/*只有一个节点*/
if (startPreorder == endPreorder)
{
if ((startInorder == endInorder) && (*startInorder == *endInorder))
{
return root;
}
else
{
throw exception("Invaild input");
}
}
//在中序遍历序列中找到根节点的值
int* rootInorder = startInorder;
while (rootInorder <= endInorder && *rootInorder != rootValue)
{
++rootInorder;
}
if (rootInorder == endInorder && *rootInorder != rootValue)
{
throw exception("Invaild input");
}
int leftLength = rootInorder - startInorder;
int* leftPreorderEnd = startPreorder + leftLength;
if (leftLength > 0)
{
//构建左子树
root->m_pLeft = ConstrcuctCore(startInorder + 1, leftPreorderEnd, startInorder, rootInorder - 1);
}
if (leftLength < endPreorder - startPreorder)
{
//构建右子树
root->m_pRight = ConstrcuctCore(leftPreorderEnd + 1, endPreorder, rootInorder + 1, endInorder);
}
return root;
}
BinaryTreeNode* Construct(int *preorder, int inorder, int length)
{
if (preorder == nullptr || inorder == nullptr || length <= 0)
return nullptr;
return ConstrcuctCore(preorder, preorder + length - 1, inorder, inorder + length - 1);
}