【代码超详解】UVA 548 Tree 树(二叉树、DFS)

【LeetCode】树的DFS(前序、中序、后序)精选10题 LeetCode 树的DFS(前序、中序、后序)精选10题 详解 阅读详情

原题:紫书 第六章 例题 6-8
第二回手写二叉树,又磕了我若干个小时,才艰难过了样例。提交的时候历经数次 WA ,然后根据紫书的代码把 DFS 的函数改了一下,AC 。

一、题目描述
输入若干个二叉树,结束标志为 EOF 。每棵二叉树占两行,分别是中序遍历和后序遍历。根据输入,输出最小路径值所在的树叶的值。已知:一条路径的值是从二叉树的根部到叶节点(包括根与叶)的每个节点的值的和。如果有多个最小的路径值,输出树叶节点的值最小的那条路径的叶节点的值。每个节点的值都是大于 0 小于 10 000 的整数,且不会重复。每棵二叉树的节点数至少为 1 , 至多为 10 000 。

二、算法分析与代码编写指导
已知一棵二叉树的中序遍历和后序遍历,可以构造出这棵二叉树。构造完毕后,再通过 DFS(深度优先搜索)找出答案。
首先,明确前序遍历、中序遍历、后序遍历的递归定义:

PreOrder(T) = T的根结点 + PreOrder(T的左子树) + PreOrder(T的右子树)
InOrder(T) = InOrder(T的左子树) + T的根结点 + InOrder(T的右子树)
PostOrder(T) = PostOrder(T的左子树) + PostOrder(T的右子树) + T的根结点
其中,+ 运算符可以表示字符串连接等运算。
在手工列写一棵二叉树的前序遍历、中序遍历、后序遍历时,先从根节点开始,套用上述定义列写,然后将表达式中的左子树、右子树再套用上述定义展开,一直处理到每个叶节点。

本题中,输入格式可以表示为:

中序遍历中,某个节点的左子树的每个节点的值分别为

该节点的右子树的每个节点的值分别为

后序遍历中,某个节点的左子树的每个节点的值分别为

该节点的右子树的每个节点的值分别为

该节点作为与其左子树、右子树直接相连的一个根节点(可以是整个二叉树的根),其值表示为:

我们以其中一个样例为代表进行演示:
3 2 1 4 5 7 6
3 1 2 5 6 7 4

后序遍历的最后一个值 4 位于树根,在中序遍历中找到 4 的位置,左边的 3 2 1 位于左子树,右边的 5 7 6 位于右子树。
中序遍历的列写顺序是:左子树→根→右子树;后序遍历的列写顺序是:左子树→右子树→根。因此,可以确定在后续中 3 1 2 属于左子树,5 6 7 属于右子树,树根分别是 2 和 7 。在中序遍历中找到 2 和 7 的位置,确定 2 的左叶节点为 3 ,右叶节点为 1 ;7 的左叶节点为 5 ,右叶节点为 6 。
将上述建树算法推广到一般情况:
后序遍历中的最后一个数 v[r] 为树根,由于每个节点的值都不同,因此可以在中序遍历中直接查找其唯一位置,取其下标(从 0 开始)记为 p 。确定在中序遍历和后序遍历中属于左子树的下标范围分别是 [0, p - 1] 和 [p + 1, t],属于右子树的下标范围分别是 [0, p-1] 和 [p, t - 1] 。其中 t 为输入数据的最后一个下标。得到下标后,再仿照之前的步骤继续处理,当 p = 0 时,左子树全部展开完毕;当 p = t 时,右子树全部展开完毕。
最终建立二叉树如图:

建立二叉树以后,通过 DFS 查找值最小的路径,并在查找到值相同的路径时记录最小的叶节点的值。
我们同样以该样例演示。
从根节点 4 出发,累计的路径值为 4 ,左边连接 2 ,先处理 2 。路径值为 6 。2 左边连接 3 ,右边 连接 1,先处理左边 3 ,路径累积为 9 。3 既没有左子节点也没有右子节点,一条路径处理完毕,路径值为 9 ,叶节点为 3 。再处理 2 的右边 1 ,累计的路径值为 7 ,叶节点为 1 。然后处理 4 的右边连接的 7 ,7 有左子节点 5 和右子节点 6 ,先进入左边,累计路径值为 16 ,叶节点为 5 。再处理右边,累计路径值为 17 ,叶节点为 6 。全部路径处理完毕,答案为 1(对应路径为 4→2→1 )。

下面开始完成代码。
主程序的大致思路是:读取→建树→处理→输出。
读取部分,用 getchar() 函数依次读取字符,读取到数字时记录节点数值,读取到空格或回车时都要保存临时记录的值。当然,也可以直接保存在数组中,不用临时变量,这会使代码执行更快。这样的代码请读者自行完成。读取到 EOF 时,退出 main 函数。
根据保存的结果建立二叉树。本程序采用指针法实现二叉树,声明一个 node 结构体,每个 node 包含该节点的值和两个 node 类型的指针,分别连接左子树和右子树。
为了防止内存泄漏,需要编写删除二叉树的函数。本例采用递归法删除,从根节点开始,依次删除左子树、右子树、节点本身。为了防止对空指针操作而出错,在函数的开头先判断,如果是空指针,直接结束函数。如果读者不理解,可以自己在草稿纸上按最后的参考代码推演删除过程。
然后写建立二叉树的代码。本例采用的建树函数返回一个 node 型指针指向建立的树根,传入的参数分别是中序遍历、后序遍历、最后的下标。先在中序遍历中查找后序遍历的最后下标的值的位置并记录,求得左子树和右子树在输入数据中的范围,然后递归调用建树函数。当不满足结束条件(最后下标 lastsubscr 等于 0 时左子树全部展开,等于原输入的最后下标时右子树全部展开)时才继续建立子树。
最后写 DFS 代码。根据上面用样例演示的算法,我们可以写出相应的代码。从根节点出发,每访问一个节点时先累加路径值,然后判定左子树或右子树是否为空,如果不为空则搜索子树。每次退回到上一节点继续搜索时,都需要用到累计到上一个节点的路径值,因此在传入的参数中加入路径值。访问完叶节点以后,要将统计的路径值减回去(重新减去该节点的值),以便统计下一条搜索路径的值。
执行完毕后,输出结果即可。
本代码留有被注释掉的测试代码。当输出的结果与预期不符而在 IDE 中查看中间变量不方便(有时候无法看到部分中间变量,比如不在循环内改变的值,map / set / vector 等容器中的值等等)时,可以在写代码的过程中额外编写输出中间结果的代码,方便找出 bug 。

AC代码:(本代码根据紫书代码优化而来,紫书代码约 60 ms ,本代码只需要约 20 ms)

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
#pragma warning(disable:4996)
struct node {
   
   
	unsigned int value; node* left, * right;
	node() :value(0), left(nullptr), right(nullptr) {
   
   }
};
Tree UVA 548 (遍历序列建立二叉树+dfs遍历) 题目链接 You are to determine the value of the leaf node in a given binary tree that is the terminal node of a path of least value from the root of the binary tree to any leaf. The value of a path is the sum of values of nodes along that path. Input The input 阅读详情

相关推荐

智能循迹小车之PID控制算法

从光电传感器获取信号确认小车和黑线的偏离角度,通过PID算法算出左右车轮速度,控制小车前进或者后退。

yzj199921的博客 4640

AMBA总线—APB总线协议详解

文章目录一、APB总线介绍1.1.什么是APB总线1.2.典型的基于 AMBA 总线的系统架构1.3.APB信号列表(重点)二、APB总线传输(时序)2.1.APB 状态机2.2.写操作(重要)2.3.读操作(重要)2.4.APB组件接口(重要)2.4.1.APB Bridge框图2.4.2.APB Slave框图三、APB到AHB的接口3.1.读操作3.2.写操作3.3.读写交替传送 一、APB...

Mr.翟的博客 4万+

AFSim 2.9实战指南:从入门到精通的中文教程

本文是AFSim 2.9的实战中文教程,旨在帮助用户从零开始掌握这一先进的仿真框架。内容涵盖从环境安装、运行第一个“Hello World”仿真,到深入理解实体、组件、想定编辑器等核心概念,并进阶探讨动力学建模、传感器仿真与红蓝对抗想定构建。最后,指南还提供了效能分析与实战排错技巧,帮助用户将仿真结果转化为有价值的量化数据,适用于军事、航空航天等领域的复杂系统行为模拟研究。

weixin_29294395的博客 360

【低空经济】低空无人机公共测试场与验证基地设计方案

公共测试场与验证基地是为低空无人机相关技术的研发、测试与应用提供一个系统性的平台。在无人机产业蓬勃发展的背景下,建设一个配备完善、功能齐全的公共测试场与验证基地显得尤为重要。该基地不仅可以作为无人机的测试和验证场地,还可以为相关企业、科研机构以及政府部门提供技术支持和服务。因此,为此基地的设计方案必须综合考虑功能性、安全性、灵活性与可持续性等多方面的因素。首先,公共测试场需划分为多个专用区域,以便满足不同类型无人机的测试需求。这包括低空飞行区域、紧急着陆区、操控模拟区和监测与数据采集区等。

2502_92579126的博客 1601

二次规划问题(qp)和序列二次规划问题(sqp)的简单理解

当二次规划的约束为非线性约束时,通常会采用sqp进行求解,用连续求解qp的方法来得到非线性约束条件下的最优解,上述的qpoases和osqp均无法直接求解非线性约束问题,所以如果使用这两个库的话,注意,sqp是结果,而不是原因,只有在非线性约束的情况下才会考虑sqp求解,如果问题本身就是线性约束,则直接用qp解就行。对于工程师而言,我们在编写代码的时候,并不关心二次规划问题的求解细节,所以一般是把二次规划问题建立好后,直接调用三方库进行求解。因为约束为非线性约束,所以先将约束进行线性化,约束原方程为。

zmhzmhzm的博客 1万+

盘点天才少年稚晖君彭志辉的知识体系

一个杰出工程师的工作区间和装备

曲折旅程,艰难人生 2万+

杰理SDK入门教程(二):USB升级程序

开发板升级操作指南 摘要:本文介绍了开发板程序升级的两种方式(常规升级和串口升级),重点说明了常规升级的操作步骤: 拨码设置:提供4种拨码方式(不拨/1档/2档/3档),对应不同指示灯状态和按键要求 硬件连接:强制升级工具需正确连接电脑和开发板(注意USB接口方向) 升级流程:根据拨码状态操作按键,观察指示灯变化(红灯常亮绿灯灭表示进入升级模式) 执行升级:运行SDK中的download.bat完成升级 文中还包含拨码开关说明、指示灯状态对照表以及升级原理说明,帮助用户理解升级过程。升级成功后在设备管理器可

qq_42014563的博客 1121

零基础学GPU KMD--8. 内存管理:GPU 显存与系统内存的协同​8.1 显存分配策略:GEM / TTM 原理

支持 VRAM、GTT(Graphics Translation Table)、SYSTEM 内存的动态迁移与缓存管理。:若缓冲区在 SYSTEM,TTM 分配 GTT 条目并建立页表映射,使 GPU 可直接访问。:系统内存中预留给 GPU 直接访问的区域,通过 GPU 的 MMU 做地址翻译。你需要我继续展开这一部分吗?​ 为复杂离散 GPU 设计,应对大容量 VRAM、多内存域、显存迁移等问题。:重量级、功能全,适合大容量、多内存域的离散 GPU,强调显存迁移与统一管理。

amy_mhd的博客 185

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

上一篇: 【代码超详解】UVA 122 Trees on the Level(二叉树、BFS)
下一篇: 【代码超详解】UVA 839 Not so Mobile
山上一缕烟
博客等级 码龄8年 269粉丝 498原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值