二叉树的后续遍历(迭代法)
迭代法实现二叉树的后续遍历
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() // 写入浏览器控制台;在控制台输出 变量…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...

让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...