码迷,mamicode.com
首页 > 其他好文 > 详细

二叉树重建(衔接上一篇二叉树基本讲解)

时间:2015-05-22 11:32:48      阅读:144      评论:0      收藏:0      [点我收藏+]

标签:二叉树重建

【题目】输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树,假设输入的前序遍历和中序遍历的结果中都不含有重复的数字,例如输入前序遍历序列{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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!