假设输入的前序遍历和中序遍历的结果中都不含重复数字。
例如:输入前序遍历序列{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;
}