news 2026/7/13 23:10:17

【例3-4】求后序遍历(信息学奥赛一本通- P1339)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【例3-4】求后序遍历(信息学奥赛一本通- P1339)

【题目描述】

输入一棵二叉树的先序和中序遍历序列,输出其后序遍历序列。

【输入】

共两行,第一行一个字符串,表示树的先序遍历,第二行一个字符串,表示树的中序遍历。树的结点一律用小写字母表示。

【输出】

一行,表示树的后序遍历序列。

【输入样例】

abdec dbeac

【输出样例】

debca

【算法笔记】由先序和中序遍历还原二叉树:别死记下标,一张草稿纸搞定

在二叉树的题目里,“已知先序和中序,求后序”属于必考的基本功。

很多同学逻辑都懂:先序找根,中序分左右。但在写代码时,往往死在递归的下标边界计算上。到底是+1还是-1?左子树的长度怎么算?一不小心就写出个死循环。

今天结合一张手写草稿,带大家彻底理顺这个逻辑,并给出顺序存储链式存储两种标准写法。

1. 核心思路:对着草稿推下标

看先序a b d e c和中序d b e a c

  • 先序第一个a是根。

  • 去中序里找到a的位置,它左边的d b e是左子树,右边的c是右子树。

难点在于:如何在先序序列里,把左子树那一段精准地“抠”出来?

关键变量定义

我们在递归函数dfs(la,ra,lb,rb)中定义:

  • la,ra:当前子树在先序中的起点和终点。

  • lb,rb:当前子树在中序中的起点和终点。

  • root:根节点在中序里的下标(用 string 的 find 找到)。

必考逻辑(请理解并背诵)

  1. 左子树有多长?

    看中序序列,从 lb 开始到 root 前面。

    所以,左子树长度 (len) = root - lb。

    (这一步算错,后面全错)

  2. 左子树的范围(递归左儿子)

    • 中序:很明显是[lb, root-1]

    • 先序:起点是根的下一个la+1。终点是起点加上长度。

    • 也就是:[la+1, la+root-lb]

  3. 右子树的范围(递归右儿子)

    • 中序:很明显是[root+1, rb]

    • 先序:紧接着左子树后面。

    • 起点:左子树终点 + 1。也就是la+(root-lb)+1

    • 终点:直接就是ra


2. 方法一:顺序存储(完全二叉树思维)

利用完全二叉树性质:节点k的左儿子下标是2*k,右儿子是2*k+1

  • 优点:逻辑简单。

  • 缺点极其浪费空间。如果是“歪脖子树”(退化成链),空间复杂度是 2^N。除非确定节点少或者满二叉树,否则慎用。

//先建树 再后序遍历输出 //方法一:顺序存储 //特点:利用2*k和2*k+1计算位置 #include<bits/stdc++.h> using namespace std; string a,b;//先序遍历 中序遍历 struct node{ int l;//记录左儿子节点的下标 int r;//记录右儿子节点的下标 char data; node(){ l=r=0; } }tre[4000];//顺序存储一定要开大数组,防止越界 void postorder(int root){//后序输出 if(tre[root].l!=0) postorder(root*2); if(tre[root].r!=0) postorder(root*2+1); cout<<tre[root].data; } void dfs(int la,int ra,int lb,int rb,int k){ //k代表所建树中根节点的下标 la ra代表本次先序遍历的起点终点 //lb rb代表本次中序遍历的起点终点 if(la>ra||lb>rb) return; int root=b.find(a[la]);//找到根节点在中序遍历输出中的位置 tre[k].data=a[la];//顺序存储记录根节点的数据 if(root>lb){//代表有左子树 tre[k].l=2*k;//顺序存储的特点 //左子树长度=root-lb,所以先序终点=la+(root-lb) dfs(la+1,la+root-lb,lb,root-1,k*2); } if(root<rb){//代表有右子树 tre[k].r=2*k+1;//顺序存储的特点 //右子树先序起点=la+左子树长度+1 dfs(la+root-lb+1,ra,root+1,rb,2*k+1); } } int main(){ cin>>a>>b; int ra=a.size(); int rb=b.size(); dfs(0,ra-1,0,rb-1,1); postorder(1); return 0; }

3. 方法二:链式存储(静态数组模拟)

打比赛最推荐的写法。

不依赖 2*k,而是用一个全局计数器 ind,用一个申请一个。哪怕树退化成一条链(世代单传二叉树),空间复杂度也只是 O(N)。

  • 原理:每次++ind给新节点发一个“身份证号”,父节点把这个号码记在lr里。

//方法二:链式存储(静态数组池) //特点:空间利用率高,通用性强 #include<bits/stdc++.h> using namespace std; string a,b; struct node{ int l; int r; char data; node(){l=r=0;} }tre[1000]; int ind=1;//链式存储存放结点位置 void postorder(int root){ if(tre[root].l!=0) postorder(tre[root].l); if(tre[root].r!=0) postorder(tre[root].r); cout<<tre[root].data; } void dfs(int la,int ra,int lb,int rb,int k){ int root=b.find(a[la]);//找到根节点在b中的位置下标 tre[k].data=a[la]; if(root>lb){//如果左子树存在 tre[k].l=++ind;//链式存储的特点:申请新节点 dfs(la+1,la+root-lb,lb,root-1,ind); } if(root<rb){//代表右子树存在 tre[k].r=++ind;//链式存储的特点:申请新节点 dfs(root-lb+la+1,ra,root+1,rb,ind); } } int main(){ cin>>a>>b; int ra=a.size()-1; int rb=b.size()-1; dfs(0,ra,0,rb,1); postorder(1); return 0; }

4. 避坑总结

  1. 关于下标:千万别死记la+root-lb这种一长串的东西。考试时像我一样在草稿纸上画一段,算出左子树长度,然后根据“起点+长度”去推,绝对不会错。

  2. 关于存储

    • 如果是平时练习或者题目保证是完全二叉树 ->用方法一(写得快)。

    • 如果是正式比赛或者不确定树的形状 ->必用方法二(稳,不爆内存)。

  3. 关于代码风格:大家注意看,我在顺序存储里也保留了tre[k].l=2*k。虽然这一步可以通过计算省略,但加上去之后,它和链式存储的逻辑就完全统一了,非常适合理解“二叉树的本质”。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/13 7:49:51

全网最全 Cursor 配置指南:从入门到高效工作流!建议收藏

全网最全 Cursor 配置指南&#xff1a;从入门到高效工作流&#xff01;建议收藏&#xff08;2025年12月最新版&#xff09; Cursor 是2025年最强大的AI代码编辑器&#xff0c;基于VS Code构建&#xff0c;深度集成Claude 3.5 Sonnet、GPT-4o等模型。正确配置能让你的开发效率提…

作者头像 李华
网站建设 2026/7/9 7:58:48

一文了解AOSP是什么?

一文了解 AOSP 是什么&#xff1f; AOSP&#xff08;Android Open Source Project&#xff0c;Android 开源项目&#xff09;是 Android 操作系统的核心开源基础&#xff0c;由 Google 主导维护。它是 Android 的“纯净版”源代码&#xff0c;任何人都可以免费下载、修改和构建…

作者头像 李华
网站建设 2026/7/9 7:59:11

盘点全球领先照明企业:技术优势与市场特色全解析

鉴于LED照明行业处于高速发展的状况下&#xff0c;许多厂家依据各自的技术积累以及市场定位&#xff0c;为全世界用户给予了丰富多样的照明解决办法。这篇文章的意图就是梳理与介绍行业里部分具有代表性最为领先的企业&#xff0c;经由剖析它们的发展进程、技术特性以及核心优势…

作者头像 李华
网站建设 2026/7/9 7:59:10

日拱一卒之最小二乘法

日拱一卒之最小二乘法 由于最小二乘法在最近出现的频率比较高&#xff0c;所以单独拎出来研究研究&#xff0c;b站上有个几何的解读&#xff0c;虽然感觉弄得不错&#xff0c;但是还是觉得有点深了&#xff0c;而且有点快&#xff0c;各种公式的嵌套看的有点乱&#xff0c;于是…

作者头像 李华
网站建设 2026/7/12 13:57:06

PS 例程大全

PS 例程大全&#x1f4da; PS 基础语法ps [options]&#x1f527; 常用选项组合组合说明输出内容ps auxBSD风格&#xff0c;最常用所有用户的所有进程ps -efUNIX/标准风格完整格式列表ps -eF扩展完整格式更多细节ps -ely长格式详细技术信息ps -ejH显示进程树层次结构ps -eLf显示…

作者头像 李华