标签:二叉树重建
【题目】输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树,假设输入的前序遍历和中序遍历的结果中都不含有重复的数字,例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},重建二叉树并输出头结点。
【分析】对根节点和左子树右子树分别分析
【根节点】前序遍历结果和中序遍历结果可以唯一确定一棵二叉树,前序遍历的过程就是从根结点开始,先访问根结点,再遍历左子树,最后右子树,从{1,2,4,7,3,5,6,8}可以看出1为根节点,中序遍历的过程是先遍历左子树,访问根节点,最后遍历右子树,从{4,7,2,1,5,3,8,6}就知道{4,7,2},{5,3,8,6}分别为根节点1的左子树和右子树,分别分析左子树和右子树。
【左子树】此时变成前序遍历序列{2,4,7},中序遍历序列{4,7,2},则对这个分支来说,2就是根节点1的左孩子,是4,7的父结点,也就是左子树分支的根结点,从{4,7,2}可以看出,{4,7}是结点2的左子树,结点2没有右子树,所以去除根节点2,考虑{4,7},很显然由前序序列{4,7},得到4作为根节点,但是从中序遍历序列看{4,7},7在4的右侧,说明4没有左子树,7是其右子树,只有7一个,所以,结点7为4的右孩子。整个以根节点1的左子树分析完毕。
【右子树】前序序列{3,5,6,8},中序序列{5,3,8,6},根节点为3,所以{5},{8,6}分别为其左右子树,左子树只有{5}所以结点5为3的左孩子,右子树前序为{6,8}中序为{8,6},根节点为6,剩下的8就是它的左孩子。整个以根节点1的右子树分析完毕。
【流程图】
将分析过程用下图来直观分析,始终变动的是root,相对各结点的子树作为根节点的变化情况,看图会更清晰,有助于对程序的理解。子树排列为左子树在左边,右子树在右边。
【二叉树重建图】
最终得到的二叉树如图所示:
【测试代码】
#include<stdio.h>
#include<stdlib.h>
typedef struct BiTreeNode
{
int data;
struct BiTreeNode *left, *right;
}Node_t;
Node_t *construct(int *startPreorder, int *endPreorder, int *startInorder, int *endInorder)
{
//前序遍历确定根节点
int rootValue= startPreorder[0];
Node_t *root =(Node_t *)malloc(sizeof(Node_t));
root->data = rootValue;
root ->left = root ->right = NULL;
if(startPreorder == endPreorder)
{
if( startPreorder == endInorder && *startPreorder == *startInorder )
return root;
}
//中序遍历确定左子树,右子树
int *rootInorder = startInorder;
while(rootInorder <= endInorder && *rootInorder != rootValue)
++rootInorder;
if(rootInorder == endInorder && *rootInorder != rootValue)
{
printf("Invalid input");
return NULL;
}
int left_length = rootInorder - startInorder;
int *left_Preorder_End = startPreorder + left_length;
if(left_length>0)
{
//rebuild left tree
root ->left = construct(startPreorder+1, left_Preorder_End, startInorder, rootInorder-1);
}
if(left_length < endPreorder - startPreorder)
{
//rebuild right tree
root ->right = construct(left_Preorder_End+1 , endPreorder, rootInorder+1, endInorder);
}
return root;
}
Node_t *create(int *preorder, int *inorder, int length)
{
if( preorder == NULL || inorder == NULL || length <= 0)
return NULL;
return construct(preorder, preorder + length -1, inorder, inorder + length -1);
}
//后序遍历
void post_order_visit(Node_t **T)
{
if(*T == NULL)
return ;
else
{
post_order_visit(&(*T)->left);
post_order_visit(&(*T)->right);
printf("%d ",(*T)->data);
}
}
int main()
{
int pre_visit[] = {1, 2, 4, 7, 3, 5, 6, 8};
int in_visit[] = {4, 7 ,2, 1, 5, 3, 8, 6};
int *preorder = pre_visit;
int *inorder = in_visit;
Node_t *root =create(preorder, inorder, 8);
post_order_visit(&root);
return 0;
}
【输出结果】
程序参考剑指offer面试6里所给程序,实现的思路符合上述分析过程,所以有助于理解,从单步调试过程可以发现所建二叉树正确无误。
标签:二叉树重建
原文地址:http://blog.csdn.net/xinyu913/article/details/45897585