参考资料:《剑指offer》
问题如下:已知二叉树的先序序列和中序序列,编写函数实现该二叉树的重建,假设二叉树中无重复元素。
假设某二叉树:
先序序列:{1,2,4,7,3,5,6,8}
中序序列:{4,7,2,1,5,3,8,6}
思路:二叉树先序遍历的第一个结点就是根节点,中序遍历根节点在中间,左边是左子树的结点,右边是右子树的结点,这样,根据两种遍历就可以确定左子树和右子树结点的先序和中序遍历序列。如1是根节点,中序序列1左边有3个结点(该三个结点也是左子树中序序列),说明先序序列1后面3个结点是左子树的先序遍历结果。通过递归,可完成整棵树的构建。
代码如下:
实现代码:
#define NULL 0
//根据先序序列和中序序列重建二叉树
BinaryTreeNode* ConstructTree(int* preOrder,int* inOrder,int length)
{
if (NULL==preOrder || NULL==inOrder || length<=0)
return NULL;
//重建根节点,先序序列第一个结点
int rootValue=preOrder[0];
BinaryTreeNode* rootNode=new BinaryTreeNode;
rootNode->m_nValve=preOrder[0];
//在中序序列中寻找根节点,计算左右子树节点数
int i;
int leftNodeNum,rightNodeNum;
for (i=0;i<length;i++)
{
if (rootValue==inOrder[i])
{
break;
}
}
leftNodeNum=i;
rightNodeNum=length-1-i;
//也可以不用判断左右结点数目
//重建左子树
if (leftNodeNum>=1)
{
rootNode->m_pLeft=ConstructTree(preOrder+1,inOrder,leftNodeNum);
}
else
{
rootNode->m_pLeft=NULL;
}
//重建右子树
if (rightNodeNum>=1)
{
rootNode->m_pRight=ConstructTree(preOrder+leftNodeNum+1,inOrder+leftNodeNum+1,rightNodeNum);
}
else
{
rootNode->m_pRight=NULL;
}
//返回根节点
return rootNode;
}
调用代码:
void main()
{
int length=8;
int preOrder[]={1,2,4,7,3,5,6,8};
int inOrder[]={4,7,2,1,5,3,8,6};
//构建树
BinaryTreeNode* pTree=ConstructTree(preOrder,inOrder,length);
//先序输出
printTreePreOrder(pTree);
printf("\n");
//中序输出
printTreeInOrder(pTree);
ReleaseTree(&pTree);
}
附其它函数代码:
//输出先序序列
void printTreePreOrder(BinaryTreeNode* pTree)
{
if (NULL==pTree)
{
return;
}
printf("%d,",pTree->m_nValve);
printTreePreOrder(pTree->m_pLeft);
printTreePreOrder(pTree->m_pRight);
}
//输出中序序列
void printTreeInOrder(BinaryTreeNode* pTree)
{
if (NULL==pTree)
{
return;
}
printTreeInOrder(pTree->m_pLeft);
printf("%d,",pTree->m_nValve);
printTreeInOrder(pTree->m_pRight);
}
//释放二叉树
void ReleaseTree(BinaryTreeNode** pTree)
{
if (NULL==(*pTree))
{
return;
}
ReleaseTree(&((*pTree)->m_pLeft));
ReleaseTree(&((*pTree)->m_pRight));
delete (*pTree);
(*pTree)=NULL;
}