问题描述:
输入二叉树的前序遍历和后序遍历结果,请重建二叉树。假设输入的前序序列和后序序列都不含重复数字。
思路分析:
在二叉树的前序遍历中第一个数字总是树的根节点的值。但是在中序遍历中根节点的值位于序列中间,左子
树节点的值位于根节点值得左边,右子树节点的值位于根节点值的右边。因此我们需要扫描中序序列擦能找
到根节点的值。通过此方法可以分别找到了左右子树的前序序列和中序序列,然后可以用递归的方法实现。
参考代码:
//根据前序序列和中序序列重建二叉树
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode *m_pLeft;
BinaryTreeNode *m_pRight;
};
BinaryTreeNode* Construct(int *preorder,int *inorder,int length)
{
if (preorder == NULL || inorder == NULL || length <= 0)
{
return NULL;
}
return ConstruceCore(preorder,preorder+length-1,inorder,inorder+length-1);
}
BinaryTreeNode* ConstruceCore(int *startPreorder,int *endPreorder,int *startInorder,int *endInorder)
{
//前序遍历的第一个节点是根节点的值
int rootValue = startPreorder[0];
BinaryTreeNode *pRoot = new BinaryTreeNode;
pRoot->m_nValue = rootValue;
pRoot->m_pLeft = pRoot->m_pRight = NULL;
if (startPreorder == endPreorder)
{//只含一个元素的前序序列和中序序列。如果在这个这个序列中值相等则是子树的根节点,不等则说明序列有问题,作为递归的终止条件
if ((startInorder == endInorder) && (*startInorder == *startPreorder))
{
return pRoot;
}
else
{
throw exception("Invalid input");
}
}
//在中序遍历中寻找根节点的值
int *rootInorder = startInorder;
while((rootInorder <= endInorder) && (*rootInorder != rootValue))
{
rootInorder++;
}
if ((rootInorder == endInorder) && (*rootInorder != *endInorder))
{
throw exception("Invalid input");
}
//根据根节点在中序序列的位置确定中序序列中左右子树的起始位置。通过计算出的左右子树长度算出
//左右子树在前序序列中的起始地址
int leftLength = rootInorder - startInorder;
int *leftPreorderEnd = startPreorder + leftLength;
if (leftLength > 0)//左子树存在时递归创建左子树
{
pRoot->m_pLeft = ConstruceCore(startPreorder+1,leftPreorderEnd,startInorder,rootInorder-1);
}
if (leftLength < endPreorder-startPreorder)//右子树存在时递归创建右子树。这个判断相当于间接判断了右子树是否存在
{
pRoot->m_pRight = ConstruceCore(leftPreorderEnd+1,endPreorder,rootInorder+1,endInorder);
}
return pRoot;
}
思考:
思想很简单,设置的变量比较多,容易混淆。特别要注意算序列起始地址。我在另一篇文章中给出了二叉树的递归遍历和
非递归遍历算法。