剑指Offer面试题:5.重建二叉树

一题目:重建二叉树二思路先根据前序遍历序列的第一个数字创建根结点,接下来在中序遍历序列中找到根结点的位置,这样就能确定左、右子树结点的数量。在前序遍历和中序遍历的序列中划分了左、右子树结点的值

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

全栈程序员社区此处内容已经被作者隐藏,请输入验证码查看内容
验证码:
请关注本站微信公众号,回复“验证码”,获取验证码。在微信里搜索“全栈程序员社区”或者“www_javaforall_cn”或者微信扫描右侧二维码都可以关注本站微信公众号。

一 题目:重建二叉树

题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示的二叉树并输出它的头结点。

         
剑指Offer面试题:5.重建二叉树

二 思路

  先根据前序遍历序列的第一个数字创建根结点,接下来在中序遍历序列中找到根结点的位置,这样就能确定左、右子树结点的数量。在前序遍历和中序遍历的序列中划分了左、右子树结点的值之后,就可以递归地去分别构建它的左右子树。

三 代码实现

(1)索引实现

struct TreeNode
{
    int data;
    TreeNode* pLeft;
    TreeNode* pRight;
};

// 重构二叉树
TreeNode* RebulidTree(int *pre, int *mid, int len)
{
    if(NULL == pre || NULL == mid || len < 0)
    {
        return NULL;
    }
    // 根据前序遍历得到根节点
    int root = pre[0];
    TreeNode *pNode = new TreeNode;
    pNode->data = root;
    pNode->pLeft = pNode->pRight = NULL;
    
    int i = 0;
    // 根据根节点将中序遍历结果分成左子树和右子树,前提肯定能找到
    for (; i < len;i ++)
    {
        if (root == mid[i])
        {
            break;
        }
    }
    if (i > 0)
    {
        int *midleft = new int[i];
        memcpy(midleft, mid, sizeof(int) * i);
        int *preleft = new int[i];
        memcpy(preleft, &pre[1], sizeof(int)*i);
        pNode->pLeft = RebulidTree(preleft, midleft, i);
        delete[] midleft;
        delete[] preleft;
    }
    if (i < len-1)
    {
        int *midright = new int[len - i - 1];
        // 将中序分配左子树,右子树
        memcpy(midright, &mid[i+1], sizeof(int)*(len-i-1));
        // 将前序分配左子树和右子树
        int *preright = new int[len-i-1];
        memcpy(preright, &pre[i + 1], sizeof(int)*(len-i-1));
        pNode->pRight = RebulidTree(preright, midright, len - i - 1);
        delete[] midright;
        delete[] preright;
    }
    
    return pNode;
}

(2)指针实现

struct TreeNode
{
    int data;
    TreeNode* pLeft;
    TreeNode* pRight;
};

TreeNode* StructNode(int *StartPre, int *EndPre, int *StartMid, int *EndMid)
{
    // 根据前序遍历得到根节点
    int nRootValue = StartPre[0];
    TreeNode *pNode = new TreeNode;
    pNode->data = nRootValue;
    pNode->pLeft = pNode->pRight = NULL;

    if (StartPre == EndPre)
    {
        if ((StartMid == EndMid) && (*StartPre == *StartMid))
        {
            return pNode;
        }
        else
        {
            throw std::exception("Invalid input");
        }
    }
    // 在中序遍历中找到根结点的值
    int *RootMid = StartMid;
    while(RootMid < EndMid && *RootMid != nRootValue)
    {
        RootMid ++;
    }
    // 若没找到,抛出异常
    if(RootMid == EndMid && *RootMid != nRootValue)
    {
        throw std::exception("Invalid input");
    }

    int nLeftLength = RootMid - StartMid;
    int *LeftPreEnd = StartPre+nLeftLength;
    if (nLeftLength > 0)
    {
        pNode->pLeft = StructNode(++StartPre, LeftPreEnd, StartMid, RootMid-1);
    }
    if (nLeftLength < EndMid - StartMid)
    {
        pNode->pRight = StructNode(LeftPreEnd+1, EndPre,  RootMid+1, EndMid);
    }
    return pNode;
}

TreeNode* RebulidTree_2 (int *pre, int *mid, int len)
{
    if(NULL == pre || NULL == mid || len < 0)
    {
        return NULL;
    }

    return StructNode(pre, pre + len -1, mid, mid+len-1);
}

void main()
{
    int pre[] = {1,2,4,7,3,5,6,8};
    int mid[] = {4,7,2,1,5,3,8,6};

    TreeNode* p =RebulidTree_2(pre, mid, 8);
    return;
}

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/120170.html原文链接:https://javaforall.net

(0)
上一篇 2021年12月19日 下午12:00
下一篇 2021年12月19日 下午12:00


相关推荐

  • kafka使用场景举例_rabbitmq和kafka的区别面试

    kafka使用场景举例_rabbitmq和kafka的区别面试Kafka使用场景

    2022年10月15日
    6
  • mybatis无效列类型_未明确定义的列

    mybatis无效列类型_未明确定义的列select*from(这里能正确执行)tmp_tbwhereROWNUM=1 数据库中的语句能正确执行,但是自动生成的语句mybatis不认识了这是因为“能正确执行的语句”中有空格数据库认识,mybatis不认识了不要写成         select字段名         ,字段名       

    2022年10月4日
    4
  • 软件测试生命周期与bug生命周期

    软件测试生命周期与bug生命周期目录一 软件测试 amp 软件开发生命周期二 描述一个 bug 三 bug 级别与生命周期四 测试执行一 软件测试 amp 软件开发生命周期 1 软件测试与软件开发的对应过程 1 需求阶段 测试人员了解需求 对需求进行分解 得出测试需求 2 计划阶段 根据需求编写测试计划或测试方案 3 设计阶段 测试人员搭建测试用例框架 根据需求和设计编写一部分测试用例 4

    2026年3月26日
    2
  • vue父传子 子传父 prop定义方法

    vue父传子 子传父 prop定义方法简单的例子没有多余代码 父传子 template 父组件引用子组件 aaa 两种写法传递 num1 num2 div aaav bind father1 num1 father2 num2 aaav bind father1 num1 father2 num2 div template script import script

    2025年11月1日
    6
  • CocosCreator 制作微信小游戏排行榜,超越好友,分享功能

    CocosCreator 制作微信小游戏排行榜,超越好友,分享功能在每局游戏结束时 用来显示玩家在好友中的排行 这个需要在微信提供的开放数据域中完成 微信为防止数据外泄 特地提供了开放数据域 开发者只能在子域获取数据 不能上传到外部 微信开放数据域中计算好排行榜数据 并显示 渲染到主域的页面上 需要在主域画布下 创建一个和画布大小相同的空物体 挂载组件子域的画面就是通过该组件渲染到挂载该组件的物体上 有点类似 Unity 的 RawIm

    2026年3月16日
    2
  • FileInputFormat.setInputPaths多路径读取规则

    FileInputFormat.setInputPaths(job,input1,input2);在读取文件时候,默认先读单个大文件所在的路径(一次性读清该文件下所有文件),后读小文件所在路径。写协同过滤时候,想让setInputPaths方法先读第一个输入路径input1,再读第二个输出路径input2就算把文件位置交换,读取的顺序还是错误publicstaticclassmyMapp…

    2022年4月6日
    36

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号