二叉树的后续遍历(迭代法)
迭代法实现二叉树的后续遍历
1、递归版本
public static void dfs(TreeNode root){if(root==null){return;}if(root.left!=null)dfs(root.left);if(root.right!=null)dfs(root.right);System.out.println(root.val);
}
从递归版本可以看出我们第一步需要遍历完所有的左节点
这里我们使用一个栈来存储树的节点,模拟递归的先进后出。
Stack<TreeNode> stack = new Stack<>();
if(root!=null){return;
}
stack.push(root);
while(!stack.isEmpty()){//遍历所有的左节点直到左节点为nullwhile(root!=null&&root.left!=null){root = root.left;stack.push(root);}//再看递归的第二步就是访问右子树。root = stack.pop(); //取出栈顶元素,准备遍历它的右子树if(root.right==null){ //说明没有右子树,就可以直接访问root节点了System.out.println(root.val);}else{//然后就又会回到上面那个while循环遍历这个右子树所有的左节点root = root.right; stack.push(root);}
}
上面就是大致的逻辑,但还有两个重要的问题没有解决。
问题1:关于左子树的重复访问。
1、当栈顶节点为3时,root = stack.pop() 。此时root指向3节点
2、然后进入while循环,又会将6号节点再次访问一遍。因为1号节点已经访问过6了。
红色箭头表示对于root节点,访问它左子树的所有左节点。
绿色箭头表示3节点,访问它左子树的所有左节点。可以看出6节点是重复访问了的。
解决方法:对于从栈中取出的节点,如果没有右子树就设置为null。
Stack<TreeNode> stack = new Stack<>();
if(root!=null){return;
}
stack.push(root);
while(!stack.isEmpty()){while(root!=null&&root.left!=null){root = root.left;stack.push(root);}root = stack.pop(); if(root.right==null){ root = null; //防止重复访问左节点System.out.println(root.val);}else{root = root.right; stack.push(root);}
}
问题2:
栈顶取出的节点有右子树的情况下,造成该节点没有被访问。
while(!stack.isEmpty()){while(root!=null&&root.left!=null){root = root.left;stack.push(root);}root = stack.pop(); if(root.right==null){ root = null;System.out.println(root.val);}else{ //含有右子树时。这时的root并没有被访问,而root也被root = root.right;覆盖掉了。所以就会造成当前节点root缺失访问。root = root.right; stack.push(root);}
}
解决方案:在root被root = root.right覆盖之前再将root存回栈中。
我们将root取出来的目的就是访问它的右子树。
while(!stack.isEmpty()){while(root!=null&&root.left!=null){root = root.left;stack.push(root);}root = stack.pop(); if(root.right==null){ root = null;System.out.println(root.val);}else{ stack.push(root); //保存当前节点root = root.right; stack.push(root); //保存当前节点的右子节点}
}
虽然解决了在栈顶取出的节点有右子树的情况下造成该节点没有被访问的问题,但又引出了一个新的问题,重复访问右子节点。
为了解决缺失访问时将2节点存入了栈两次。
1、一次是遍历所有左子树的所有左子节点加入的。(这次的加入目的是用来遍历该节点右子树的)
2、一次是为了解决缺失访问又将2节点存入栈中。(这次的目的是为了在遍历完右子树后再访问2节点用的。因为是后序遍历)
通过代码可以看出,如果我们不加以限制,那么这个2节点就会第三次,第四次…入z栈造成重复访问。
我们的需求是对于有右子树的节点只访问两次。所以我们可以引入一个标记。
TreeNode pre = null
pre变量的作用就是标识该节点的右子树是否已经遍历过了,如果遍历过了。我们就不将其再次入栈了。
当pre==root.right说明右子树已经访问过了。
最终版本
//这个pre防止重复遍历右子树
TreeNode pre = null;while(!stack.isEmpty()){while (root!=null&&root.left != null) {root = root.left;stack.push(root);}root = stack.pop();//pre==root.rightif(root.right==null||pre==root.right){pre = root;System.out.println(root.val);//这个root设置为null防止重复遍历左子树root = null;}else{stack.push(root);root = root.right;stack.push(root);}}
如果节点2的右子树等于pre就说明这个右子树已经访问过了。2节点的左右子树都访问完就可以按照同样操作继续处理1节点了。
从图中可以看出pre指针是从下往上一步一步传递上去的。
相关文章:

二叉树的后续遍历(迭代法)
迭代法实现二叉树的后续遍历 1、递归版本 public static void dfs(TreeNode root){if(rootnull){return;}if(root.left!null)dfs(root.left);if(root.right!null)dfs(root.right);System.out.println(root.val); }从递归版本可以看出我们第一步需要遍历完所有的左节点 这里我…...

CVE-2021-41773/42013 apache路径穿越漏洞
影响范围 CVE-2021-41773 Apache HTTP server 2.4.49 CVE-2021-42013 Apache HTTP server 2.4.49/2.4.50 漏洞原理 Apache HTTP Server 2.4.49版本使用的ap_normalize_path函数在对路径参数进行规范化时会先进行url解码,然后判断是否存在…/的路径穿越符…...
前端性能测试工具WebPagetest
简介:一款web性能在线性能评测工具,可测试有关页面在各种条件下的性能,并且提供深入诊断信息。 WebPagetest 的主页:https://www.webpagetest.org/,也就是工具的使用界面。 注意:WebPageTest 并不是完全免…...
易语言软件定制软件开发脚本开发协议软件电脑网站APP应用视频制作工程制作
随着信息技术的不断发展,易语言软件定制开发已成为许多公司的一项重要业务。本文将探讨如何利用易语言承接软件定制软件开发脚本开发协议软件电脑网站APP应用视频制作工程制作。 一、易语言概述 易语言是一种简单易学的编程语言,它采用中文编程ÿ…...
Windows上配置IP端口转发
在通常涉及到使用网络地址转换(NAT)规则,可以使用一些工具和命令行选项来实现。以下是在Windows上配置端口转发的一般步骤: **注意:端口转发需要管理员权限,因此请确保以管理员身份运行命令行工具。** 1.…...

韦东山D1S板子——汇编启动代码第一行分析(.long 0x0300006f)
1、汇编启动源码 2、分析二进制:0x0300006f 2.1、反汇编代码 2.2、jal指令 jal指令的作用:跳转到当前PC值偏移offset处执行,其中offset由jal指令的bi[31:12]表示; 2.3、分析指令:j 20030 <reset> j 20030 //伪…...

了解单域名证书和通配符证书的区别,选择合适的SSL证书解决方案
随着互联网的不断发展,网站安全性问题一直备受关注,在保护网站数据安全的过程中,SSL证书一直发挥着至关重要的作用。而在选择SSL证书时,单域名证书和通配符证书是两种常见的选择。本文将详细介绍单域名证书和通配符证书的区别&…...

【LeetCode】7. 整数反转
题目链接 文章目录 Python3官方解法 ⟮ O ( ∣ x ∣ ) 、 O ( 1 ) ⟯ \lgroup O(|x|)、O(1)\rgroup ⟮O(∣x∣)、O(1)⟯写法2写法3 C官方解法 ⟮ O ( ∣ x ∣ ) 、 O ( 1 ) ⟯ \lgroup O(|x|)、O(1)\rgroup ⟮O(∣x∣)、O(1)⟯ Python3 官方解法 ⟮ O ( ∣ x ∣ ) 、 O ( 1…...

防止请求重复提交:注解+拦截器的实现方案
文章目录 了解请求重复提交解决思路具体实现 了解请求重复提交 请求重复提交是指用户在一次请求还未处理完成时,重复提交了相同的请求。这种情况通常发生在网络延迟、用户误操作或系统性能不佳等情况下。 请求重复提交可能会导致以下问题和影响: 数据不…...

C#使用mysql-connector-net驱动连接mariadb报错
给树莓派用最新的官方OS重刷了一下,并且用apt install mariadb-server装上“mysql”作为我的测试服务器。然后神奇的事情发生了,之前用得好好的程序突然就报错了,经过排查,发现在连接数据库的Open阶段就报错了。写了个最单纯的Con…...

SpringBoot 定时任务:@EnableScheduling @Scheduled
Scheduled注解参数 cron参数 这个参数是最经常使用的参数,表示接收一个cron参数,cron它是一个表达式,最多接收7个参数,从左到右分别表示:秒 分 时 天 月 周 年;参数以空格隔开,其中年不是必须参…...
Jquery 如何获取子元素。如何找到所有 HTML select 标签的选中项。jQuery 里的 ID 选择器和 class 选择器有何不同
可以使用 jQuery 的子选择器(Child Selector)或 find() 方法来获取子元素。 子选择器(Child Selector): 使用父元素的选择器和 > 符号来选取该父元素的子元素。 例如:选取 id 为 parent 的元素内所有 cl…...

Python Selenium 之数据驱动测试的实现!
数据驱动模式的测试好处相比普通模式的测试就显而易见了吧!使用数据驱动的模式,可以根据业务分解测试数据,只需定义变量,使用外部或者自定义的数据使其参数化,从而避免了使用之前测试脚本中固定的数据。可以将测试脚本…...

【Proteus仿真】【STM32单片机】智能语音家居陪护机器人
文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真STM32单片机控制器,使用OLED显示模块、红外传感器、蜂鸣器、DS18B20温度传感器,风扇LED、语音识别模块等。 主要功能: 系统运行后,…...

C#上位机序列10: 批量读写+点对点更新+数据类型处理
一、源码结构 二、运行效果 三、源码解析 PLC批量读写点对点更新数据类型处理 优点:根据数据类型,判定监听的地址范围(40120_int 监听两个word:40120 40121;40130_long 监听四个word:40130 40131 40132 4…...

MySQL 概述 数据库表操作 数据增删改
目录 MySQL概述前言安装与配置MySQL登录与卸载 数据模型概述SQL简介SQL通用语法简介SQL分类 数据库设计(数据库操作)-DDL数据库操作查询数据库 show databases、select database()创建数据库 create database使用数据库 use删除数据库 drop database 图形化工具连接数据库操作数…...

存储器概述
一、存储系统基本概念...

Fabric.js 使用自定义字体
本文简介 点赞 关注 收藏 学会了 如果你使用 Fabric.js 做编辑类的产品,有可能需要给用户配置字体。 这次就讲讲在 Fabric.js 中创建文本时怎么使用自定义字体、在项目运行时怎么修改字体、以及推荐一个精简字体库的工具。 学习本文前,你必须有一点…...

【C++项目】高并发内存池第七讲性能分析
目录 1.测试代码2.代码介绍3.运行结结果 1.测试代码 #include"ConcurrentAlloc.h" #include"ObjectPool.h" #include"Common.h" void BenchmarkMalloc(size_t ntimes, size_t nworks, size_t rounds) {std::vector<std::thread> vthread(…...
【JavaScript】快速学习JS
JS区分大小写,后面的分号可有可无; 输出语句 window.alter() // 写入警告框;在浏览器中的警告弹窗输出 document.write() // 写入html输出;在html页面中输出 console.log() // 写入浏览器控制台;在控制台输出 变量…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...

华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散
前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说,在叠衣服的过程中,我会带着团队对比各种模型、方法、策略,毕竟针对各个场景始终寻找更优的解决方案,是我个人和我司「七月在线」的职责之一 且个人认为,…...
xmind转换为markdown
文章目录 解锁思维导图新姿势:将XMind转为结构化Markdown 一、认识Xmind结构二、核心转换流程详解1.解压XMind文件(ZIP处理)2.解析JSON数据结构3:递归转换树形结构4:Markdown层级生成逻辑 三、完整代码 解锁思维导图新…...
GeoServer发布PostgreSQL图层后WFS查询无主键字段
在使用 GeoServer(版本 2.22.2) 发布 PostgreSQL(PostGIS)中的表为地图服务时,常常会遇到一个小问题: WFS 查询中,主键字段(如 id)莫名其妙地消失了! 即使你在…...
深度解析云存储:概念、架构与应用实践
在数据爆炸式增长的时代,传统本地存储因容量限制、管理复杂等问题,已难以满足企业和个人的需求。云存储凭借灵活扩展、便捷访问等特性,成为数据存储领域的主流解决方案。从个人照片备份到企业核心数据管理,云存储正重塑数据存储与…...

职坐标物联网全栈开发全流程解析
物联网全栈开发涵盖从物理设备到上层应用的完整技术链路,其核心流程可归纳为四大模块:感知层数据采集、网络层协议交互、平台层资源管理及应用层功能实现。每个模块的技术选型与实现方式直接影响系统性能与扩展性,例如传感器选型需平衡精度与…...

react-pdf(pdfjs-dist)如何兼容老浏览器(chrome 49)
之前都是使用react-pdf来渲染pdf文件,这次有个需求是要兼容xp环境,xp上chrome最高支持到49,虽然说iframe或者embed都可以实现预览pdf,但为了后续的定制化需求,还是需要使用js库来渲染。 chrome 49测试环境 能用的测试…...