题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{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;
};
BinaryTreeNode* Construct(int* preorder, int* inorder, int length){ //length为二叉树中的节点数目
if(preorder == nullptr || inorder == nullptr || length <= 0)
return nullptr;
return ConstructCore(preorder, preorder + length - 1, inorder, inorder + length - 1); //参数分别为前序遍历和中序遍历序列的始末下标
}
BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder, int* startInorder, int* endInorder){
//前序遍历序列的第一个数字是根节点的值
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.");
}
//在中序遍历中找到根节点的值
int* rootInorder = startInorder;
while(rootInorder <= endInorder && *rootInorder != rootValue)
rootInorder++; //根节点在中序遍历中的位置为rootInorder
if(rootInorder == endInorder && *rootInorder != rootValue)
throw std::exception("invalid input.");
int leftLength = rootInorder - startInorder; //左子树的长度
int* leftPreorderEnd = startInorder + leftLength; //左子树在先序遍历中的截止位置
if(leftLength > 0){
//构建root的左子树
root->m_pLeft = ConstructCore(startPreorder + 1, leftPreorderEnd, startInorder, rootInorder-1);
}
if(leftLength < endPreorder - endPreorder){ //先序遍历中存在右子树部分
//构建root的右子树
root->m_pRight = ConstructCore((leftPreorderEnd + 1, endPreorder, rootInorder + 1, endInorder);
}
return root;
}
核心函数为ConstructCore,在其中先根据前序遍历序列中的第一个数字创建根节点,然后在中序遍历序列中找到根节点的位置,从而确定左、右子树节点的数量,前序遍历和中序遍历序列中划分了左、右子树节点的值之后,采用递归调用函数ConstructCore去分别构建它的左、右子树,直至重建完成。