【算法/c++】利用中序遍历和后序遍历建二叉树

news2025/4/18 7:53:42

目录

  • 题目:树的遍历
    • 前言
    • 题目来源
    • 树的数组存储
      • 基本思想
      • 存储规则
      • 示例
    • 建树算法
      • 关键思路
      • 代码
      • 总代码
    • 链表法

题目:树的遍历

前言

如果不是完全二叉树,使用数组模拟树,会很浪费空间。

题目来源

本题来自 PTA 天梯赛。
题目链接: 树的遍历

题目描述
给定一棵二叉树的后序遍历和中序遍历序列,输出其层序遍历的序列。假设树中节点的键值均为互不相同的正整数。

输入格式

  • 第一行:一个正整数 N(≤30),表示二叉树的节点个数。
  • 第二行:后序遍历序列,数字间以空格分隔。
  • 第三行:中序遍历序列,数字间以空格分隔。

输出格式

  • 输出层序遍历序列,数字间以 1 个空格分隔,行首尾不得有多余空格。

输入样例

7
2 3 1 5 7 6 4
1 2 3 4 5 6 7

输出样例

4 1 6 3 5 7 2

树的数组存储

基本思想

通过数组的索引关系表示树的父子结构,无需显式存储指针。

存储规则

  1. 根节点存储在索引 1(注意不是 0)。
  2. 对于任意节点 i
    • 左子节点索引2 * i
    • 右子节点索引2 * i + 1
    • 父节点索引i / 2(整数除法)

示例

假设有一棵二叉树:
在这里插入图片描述
我们可以通过一个数组去存储
在这里插入图片描述
树的索引对应数组的索引,树节点的值存在数组里。

建树算法

关键思路

  • 后序遍历:最后一个元素是根节点
  • 中序遍历:根节点左边是左子树,右边是右子树
  • 递归构建:分别处理左右子树

后序遍历:
结构: 左子树 — 右子树 — 根

中序遍历:
结构: 左子树,根,右子树

我们通过中序遍历找到根,就能知道左子树的个数,那么我们就能找到后序遍历左子树的范围,从而得知左子树的根。右子树同理。

算法过程:

1.确定根节点:

  • 从后序遍历序列中取出最后一个元素,这就是当前子树的根节点
  • 将这个根节点存入我们构建的树结构中

2.在中序序列中定位根节点:

  • 在中序遍历序列中查找这个根节点的位置
  • 这个位置将中序序列分为左子树和右子树两部分

3.递归构建左右子树

代码

参数说明

  • root 后序序列中当前子树的根节点索引
  • start 中序序列中当前子树的起始索引
  • ed 中序序列中当前子树的结束索引
  • idx 当前节点在tree数组中的存储位置

变量说明

  • post 为后序遍历数组
  • in 为中序遍历数组
  • tree为存储树的数组
//根据中序遍历和后续遍历构造树
void build(int root,int start,int ed,int idx)
{
    if(start>ed) return;

    //后序知道树根,直接构造数组树
    tree[idx] = post[root];

    //在中序遍历中找根位置,用来区分后序遍历左右子树位置
    int i = start;
    while(i<ed && in[i] != post[root]) i++;

    //构造左子树
    build(root - ed+i-1,start,i-1,idx*2);
    //构造右子树
    build(root - 1,i+1,ed,idx*2+1);
}

总代码

#include <iostream>
using namespace std;
#include <vector>

const int N = 1e5+10;
int n;
int post[N],in[N];
vector<int> tree(N,-1);

//根据中序遍历和后续遍历构造树
void build(int root,int start,int ed,int idx)
{
    if(start>ed) return;

    //后序知道树根,直接构造数组树
    tree[idx] = post[root];

    //在中序遍历中找根位置,用来区分后序遍历左右子树位置
    int i = start;
    while(i<ed && in[i] != post[root]) i++;

    //构造左子树
    build(root - ed+i-1,start,i-1,idx*2);
    //构造右子树
    build(root - 1,i+1,ed,idx*2+1);
}


int main()
{
    cin  >> n;
    for(int i = 1;i<=n;i++)
        cin >>  post[i];
    for(int i = 1;i<=n;i++)
        cin >> in[i];

    build(n,1,n,1);

    vector<int> ans;
    for(int i = 1;i<tree.size();i++)
        if(tree[i] !=-1) ans.push_back(tree[i]);

    for(int i = 0;i<ans.size();i++)
        if(i != ans.size()-1)cout << ans[i]  <<  ' ';
        else cout << ans[i];

    return 0;
}

链表法

思路是差不多的

#include <iostream>
#include <queue>

using namespace std;
const int N  =50;
int n;
int post[N],in[N];

struct node
{
    int val;
    node* left;
    node* right;
};

node* build(int root,int start,int ed)
{
   if(start>ed) return nullptr;

    //创建结点
    node * p = (node *) malloc(sizeof(node));
    p->val = post[root];

    //在中序遍历中找根位置,用来区分后序遍历左右子树位置
    int i = start;
    while(i<ed && in[i] != post[root]) i++;

    p->left = build(root - ed+i-1,start,i-1);
    p->right = build(root - 1,i+1,ed);

    return p;
}


void dfs(node *p)
{
    queue<node> q;
    q.push(*p);
    while(q.size())
    {
        node temp = q.front();
        q.pop();
        if(temp.val != p->val)cout << " ";
        cout << temp.val;
        if(temp.left != nullptr)  q.push(*temp.left);
        if(temp.right != nullptr) q.push(*temp.right);
    } 
}

int main()
{
    cin >> n;
    for(int i = 1;i<=n;i++)
        cin >>  post[i];
    for(int i = 1;i<=n;i++)
        cin >> in[i];

    node* head = build(n,1,n);

    dfs(head);

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2329847.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于论文的大模型应用:基于SmartETL的arXiv论文数据接入与预处理(一)

1. 背景 arXiv简介&#xff08;参考DeepSeek大模型生成内容&#xff09;&#xff1a; arXiv&#xff08;发音同“archive”&#xff0c;/ˈɑːrkaɪv/&#xff09;是一个开放的学术预印本平台&#xff0c;主要用于研究人员分享和获取尚未正式发表或已完成投稿的学术论文。创…

cpp经典数论问题

题目如下 思路 代码如下

C++中如何比较两个字符串的大小--compare()函数实现

一、现在有一个问题描述&#xff1a;有两个字符串&#xff0c;要按照字典顺序比较它们的大小&#xff08;注意所有的小写字母都大于所有的大写字母 &#xff09;。 二、代码 #include <bits/stdc.h> using namespace std;int main() {string str1 "apple";…

Scala面向对象2

1. 抽象属性和方法&#xff1a;用 abstract 关键字定义抽象类&#xff0c;其中抽象属性无初始值&#xff0c;抽象方法无实现 。重写抽象方法需用 override &#xff0c;重写抽象属性时&#xff0c;可变属性用 var &#xff0c;不可变属性用 val 。 匿名子类&#xff1a;和 Jav…

【FPGA基础学习】状态机思想实现流水灯

目录 一、用状态机实现LED流水灯1.状态机思想简介1. 1基本概念1.2.核心要素1.3分类与模型 2.LED流水灯 二、CPLD与FPGA1.技术区别2.应用场景3.设计选择建议 三、HDLbits组合逻辑题目 一、用状态机实现LED流水灯 1.状态机思想简介 1. 1基本概念 ​ 状态机&#xff08;Finite …

图片尺寸修改软件下载

【图片尺寸调整工具v1.0&#xff1a;高效便捷的图像处理助手】 图片尺寸调整工具v1.0是一款专为简化图像处理流程设计的轻量级软件&#xff0c;兼顾高效批量处理与个性化单图调整需求。该工具以"零学习成本"为核心设计理念&#xff0c;通过简洁直观的交互界面&#…

MySQL-SQL-DDL语句、表结构创建语句语法、表约束、表数据类型,表结构-查询SQL、修改SQL、删除SQL

一.SQL SQL&#xff1a;一门操作关系型数据库的编程语言&#xff0c;定义操作所有关系型数据库的统一标准 二. DDL-数据库 1. 查询所有数据库 命令&#xff1a;show databases; 2. 查询当前数据库 命令&#xff1a;select database(); 3. 创建数据库 命令&#xff1a;create da…

网络钓鱼攻击的威胁和执法部门的作用(第一部分)

在当今的数字世界中&#xff0c;网络犯罪分子不断开发新技术来利用个人、企业和政府机构。 最普遍和最具破坏性的网络犯罪形式之一是网络钓鱼——一种社会工程手段&#xff0c;用于欺骗人们提供敏感信息&#xff0c;例如登录凭据、财务数据和个人详细信息。 随着网络钓鱼攻击…

鸿蒙版(ArkTs) 贪吃蛇,包含无敌模式 最高分 暂停和继续功能

鸿蒙版(ArkTs) 贪吃蛇&#xff0c;包含无敌模式 最高分 暂停和继续功能; 效果图如下&#xff1a; 代码如下&#xff1a; // 所有import语句必须放在文件开头 import router from ohos.router; import promptAction from ohos.promptAction; // Add this import at the top wit…

解决Win11耳机没有声音的问题

方法一&#xff1a;更新驱动程序&#xff08;有效&#xff09; 进入 “设置”&#xff08;快捷键&#xff1a;WinX&#xff09;&#xff0c;点击 “Windows 更新” → “高级选项” 点击 “可选更新” &#xff0c;然后点击 “驱动程序更新” 【注】&#xff1a;更新后可能会出…

【spring02】Spring 管理 Bean-IOC,基于 XML 配置 bean

文章目录 &#x1f30d;一. bean 创建顺序&#x1f30d;二. bean 对象的单例和多例❄️1. 机制❄️2. 使用细节 &#x1f30d;三. bean 的生命周期&#x1f30d;四. 配置 bean 的后置处理器 【这个比较难】&#x1f30d;五. 通过属性文件给 bean 注入值&#x1f30d;六. 基于 X…

内网渗透(杂项集合) --- 中的多协议与漏洞利用技术(杂项知识点 重点) 持续更新

目录 1. NetBIOS 名称的网络协议在局域网中内网渗透中起到什么作用 2. 使用 UDP 端口耗尽技术强制所有 DNS 查找失败&#xff0c;这个技术如何应用在局域网内网渗透测试中 3. 在本地创建一个 HTTP 服务来伪造 WPAD 服务器 什么是 WPAD 服务器&#xff1f;这个服务器是干嘛的…

el-tabs添加按钮增加点击禁止样式

前置文章 一、vue使用element-ui自定义样式思路分享【实操】 二、vue3&ts&el-tabs多个tab表单校验 现状确认 点击添加按钮&#xff0c;没有点击样式&#xff0c;用户感知不明显没有限制最大的tab添加数量&#xff0c;可以无限添加 调整目标&代码编写 调整目标…

LINUX 5 vim cat zip unzip

dd u撤销 ctrlr取消撤销 q!刚才的操作不做保存 刚才是编辑模式 现在是可视化模式 多行注释

PDFBox渲染生成pdf文档

使用PDFBox可以渲染生成pdf文档&#xff0c;并且自定义程度高&#xff0c;只是比较麻烦&#xff0c;pdf的内容位置都需要手动设置x&#xff08;横向&#xff09;和y&#xff08;纵向&#xff09;绝对位置&#xff0c;但是每个企业的单据都是不一样的&#xff0c;一般来说都会设…

Batch Normalization:深度学习训练的加速引擎

引言 在深度学习的发展历程中&#xff0c;训练深度神经网络一直是一项极具挑战性的任务。随着网络层数的增加&#xff0c;梯度消失、梯度爆炸以及训练过程中的内部协变量偏移&#xff08;Internal Covariate Shift&#xff09;问题愈发严重&#xff0c;极大地影响了模型的收敛…

低空经济基础设施建设方向与展望

随着科技的不断进步&#xff0c;低空经济正逐渐成为推动国家经济发展的新引擎。低空经济&#xff0c;指的是在低空范围内进行的各种经济活动&#xff0c;包括但不限于无人机物流、空中交通管理、低空旅游、农业监测等。本文将探讨低空经济基础设施建设的方向与未来展望。 1. 低…

如何保证RabbitMQ消息的可靠传输?

在这个图中&#xff0c;消息可能丢失的场景是1&#xff0c;2&#xff0c;3 1.在生产者将消息发送给RabbitMQ的时候&#xff0c;消息到底有没有正确的到达服务器呢&#xff0c;RabbitMQ提供了两种解决方案&#xff1a; a. 通过事务机制实现&#xff08;比较消耗性能&#xff0…

Sentinel核心源码分析(上)

文章目录 前言一、客户端与Spring Boot整合二、SphU.entry2.1、构建责任链2.2、调用责任链2.2.1、NodeSelectorSlot2.2.2、ClusterBuilderSlot2.2.3、LogSlot2.2.4、StatisticSlot2.2.5、AuthoritySlot2.2.6、SystemSlot2.2.7、FlowSlot2.2.7.1、selectNodeByRequesterAndStrat…

Systemd安全加密备份系统与智能通知

实训背景 你是一家金融科技公司的系统架构师&#xff0c;需为敏感数据设计一套安全备份系统&#xff0c;满足以下需求&#xff1a; 加密存储&#xff1a;自动解密插入的LUKS加密USB设备&#xff0c;挂载到安全目录。备份验证&#xff1a;备份完成后校验文件完整性&#xff0c…