《剑指Offer》面试题7
1 问题
题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1, 2, 4, 7, 3, 5, 6, 8}和中序遍历序列{4, 7, 2, 1, 5, 3, 8, 6},则重建出
/* 1
* 2 3
* 4 5 6
* 7 8
2 分析(递归思想)
1.根据二叉树前序遍历的特点,遍历结果中第一个节点是树的根节点,确定根节点的值val。
2.然后根据val,在中序遍历的结果中寻找根节点的位置,根据规律:左子树节点 -> 根节点 -> 右子树节点,确定左右节点的数量
3.再根据左右节点的数量,得出前序遍历结果:根节点 -> 左子树节点 -> 右子树节点
有了上述规律,总结递推公式(分别对左右子树进行,不断缩小问题范围)、回归条件(没有左右子树了,所有根节点确认完毕)
3 代码
BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder, int* startInorder, int* endInorder);
//功能:根据二叉树前序和中序遍历结果,重建二叉树
//输入:preorder前序遍历数组首地址、inorder中序遍历数组首地址、length节点个数
//返回:根节点指针
BinaryTreeNode* Construct(int* preorder, int* inorder, int length)
{
if(preorder == nullptr || inorder == nullptr || length <= 0)
return nullptr;
return ConstructCore(preorder, preorder + length - 1,
inorder, inorder + length - 1);
}
//功能:递归实现二叉树重建
//输入: startPreorder前序遍历数组首地址、endPreorder前序遍历数组尾地址
// startInorder中序遍历数组首地址、endInorder中序遍历数组尾地址
//返回:根节点指针
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 = nullptr;
if(startPreorder == endPreorder)
{//考虑只有一个根节点的情况
if(startInorder == endInorder && *startPreorder == *startInorder)
return root;
else
throw std::exception("Invalid input.");
}
// 2.在中序遍历中找到根结点的值
int* rootInorder = startInorder;
while(rootInorder <= endInorder && *rootInorder != rootValue)
++ rootInorder;
if(rootInorder == endInorder && *rootInorder != rootValue)
throw std::exception("Invalid input.");
// 3.在前序遍历结果中确定左子树节点的数量
int leftLength = rootInorder - startInorder;
int* leftPreorderEnd = startPreorder + leftLength;
if(leftLength > 0)
{//4.对左子树进行递归,构建左子树
root->m_pLeft = ConstructCore(startPreorder + 1, leftPreorderEnd,
startInorder, rootInorder - 1);
}
if(leftLength < endPreorder - startPreorder)
{//对右子树进行递归,构建右子树
root->m_pRight = ConstructCore(leftPreorderEnd + 1, endPreorder,
rootInorder + 1, endInorder);
}
return root;
}