迭代实现二叉树的遍历-算法通关村

迭代实现二叉树的遍历-算法通关村


  • 理论上,递归能做的迭代一定能做,但可能会比较复杂。有时候面试官要求不使用递归实现三种遍历,递归就是每次执行方法调用都会先把当前的局部变量、参数值和返回地址等压入栈中,后面在递归返回的时候,从栈顶弹出上一层的各项参数继续执行,这就是递归为什么可以自动返回并执行上一层方法的原因。

1 迭代法实现前序遍历

  • 前序遍历是中左右,如果还有左子树就一直向下找。完了之后再返回从最底层逐步向上向右找。
    不难写出如下代码:(注意代码中,空节点不入栈)

  •   public List<Integer> preOrderTraversal(TreeNode root){
              List<Integer> res = new ArrayList<>();//存放遍历的结果
              if(root == null){
                  return res;
              }
              Deque<TreeNode> stack = new LinkedList<>();
              TreeNode node = root;
              while(!stack.isEmpty() || node != null){
                  while(node != null){//空节点不入栈
                      res.add(node.val);
                      stack.push(node);
                      node = node.left;
                  }
                  //当当前节点的所有左子节点都已遍历后,
                  // 将栈顶元素出栈,并将node更新为该节点的右子节点。
                  // 然后继续执行内部循环,遍历右子树。
                  node = stack.pop();
                  node = node.right;
              }
              return res;
          }
    

2 迭代法实现中序遍历

  • 中序遍历是左中右,先访问的是二叉树左子树的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进res列表中)。在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。看代码:

  •   public List<Integer> inOrderTraversal(TreeNode root){
              List<Integer> res = new ArrayList<>();
              Deque<TreeNode> stack = new LinkedList<>();
              while(!stack.isEmpty() || root != null){
                  while(root != null){
                      //将当前节点入栈,并将root更新为其左子节点。
                      // 这个循环会一直执行,直到当前节点为空,
                      // 即遍历完当前节点的所有左子节点。
                      stack.push(root);
                      root = root.left;
                  }
                  root = stack.pop();
                  res.add(root.val);
                  //将root更新为该节点的右子节点,以便后续遍历右子树
                  root = root.right;
              }
              return res;
          }
    

3 迭代法实现后序遍历

  • 后序遍历的非递归实现有三种基本的思路:反转法、访问标记法、和Morris法,可惜三种理解起来都有些难度,如果头发不够,可以等一等再学习。
    个人感觉访问标记法是最难理解的方法,而Morris法是一个老外发明的巧妙思想:不使用栈,而是用好树中的nul指针,但是实现后序仍然非常麻烦,我们这里不再展开,感兴趣的同学可以查一
    下。

  • 这里只介绍一种好理解又好实现的方法:反转法

  • 如下图,我们先观察后序遍历的结果是 seq = { 9 5 7 4 3 },如果我们将其整体反转的话就是
    new_seq = {3 4 7 5 9}.

  • 有没有发现要得到new_seq的方法和前序遍历思路几乎一致,只不过是左右反了。前序是先中间,再左边然后右边,而这里是先中间,再后边然后左边。那我们完全可以改造一下前序遍历,得到序列new_seq之后再reverse一下就是想要的结果了,代码如下:

  •   public List<Integer> postOrderTraversal(TreeNode root){
              List<Integer> res = new ArrayList<>();
              if(root == null){
                  return res;
              }
              Deque<TreeNode> stack = new LinkedList<>();
              TreeNode node = root;
              while(!stack.isEmpty() || node != null){
                  //将当前节点的值添加到结果列表res中,
                  // 然后将当前节点入栈,并将node更新为其右子节点。
                  // 这个循环会一直执行,直到当前节点为空
                  while(node != null){
                      res.add(node.val);
                      stack.push(node);
                      node = node.right;
                  }
                  node = stack.pop();
                  //将node更新为该节点的左子节点,以便后续遍历左子树。
                  node = node.left;
              }
              //列表中的顺序是左子树-右子树-根节点。
              // 但是后序遍历的正确顺序应该是左子树-右子树-根节点,
              // 所以需要将结果列表res反转。
              Collections.reverse(res);
              return res;
          }
    
    
    
    

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

uniapp 使用命令行创建vue3 ts 项目

命令行创建 uni-app 项目&#xff1a; vue3 ts 版 npx degit dcloudio/uni-preset-vue#vite-ts 项目名称注意 Vue3/Vite版要求 node 版本^14.18.0 || >16.0.0 如果下载失败&#xff0c;请去gitee下载 https://gitee.com/dcloud/uni-preset-vue/repository/archive/vite-ts…

基于nodejs+vue的Spark的共享单车数据存储系统的设计与实现python-flask-django-php

本文拟采用nodejs技术和express搭建系统框架&#xff0c;后台使用MySQL数据库进行信息管理&#xff0c;设计开发的共享单车数据存储系统。通过调研和分析&#xff0c;系统拥有管理员和用户两个角色&#xff0c;主要具备个人中心、用户管理、共享单车管理、系统管理等功能模块。…

力扣爆刷第105天之CodeTop100五连刷11-15

力扣爆刷第105天之CodeTop100五连刷11-15 文章目录 力扣爆刷第105天之CodeTop100五连刷11-15一、5. 最长回文子串二、33. 搜索旋转排序数组三、102. 二叉树的层序遍历四、200. 岛屿数量五、121. 买卖股票的最佳时机 一、5. 最长回文子串 题目链接&#xff1a;https://leetcode…

Unity VisionOS开发流程

Unity开发环境 Unity Pro, Unity Enterprise and Unity Industry 国际版 Mac Unity Editor(Apple silicon) visionOS Build Support (experimental) 实验版 Unity 2022.3.11f1 NOTE: 国际版与国服版Pro账通用&#xff0c;需要激活Pro的许可证。官方模板v0.6.2,非Pro版本会打…

微软开源项目Garnet:Redis的竞争者还是替代者?

对于开源社区&#xff0c;最近的一大新闻就是Redis宣布从7.4版本开始&#xff0c;将采用Redis源代码可用许可证&#xff08;RSALv2&#xff09;和服务器端公共许可证&#xff08;SSPLv1&#xff09;的双重许可证&#xff0c;取代原有的BSD三条款许可证。这一变化引发了开发者社…

【P1328】[NOIP2014 提高组] 生活大爆炸版石头剪刀布

[NOIP2014 提高组] 生活大爆炸版石头剪刀布 题目背景 NOIP2014 提高组 D1T1 题目描述 石头剪刀布是常见的猜拳游戏&#xff1a;石头胜剪刀&#xff0c;剪刀胜布&#xff0c;布胜石头。如果两个人出拳一样&#xff0c;则不分胜负。在《生活大爆炸》第二季第 8 集中出现了一种…

Google AI 肺癌筛查的计算机辅助诊断

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

搭建Hadoop HA

目录 前言 搭建前准备 搭建 前言 Hadoop是一个由Apache基金会所开发的分布式系统基础架构&#xff0c;它允许用户在不了解分布式底层细节的情况下开发分布式程序&#xff0c;充分利用集群的威力进行高速运算和存储。Hadoop主要解决大数据存储和大数据分析两大核心问题&…

Java/JSP界面实现多国语言支持,支持插入变量,还要考虑名词单复数

在Java/JSP中&#xff0c;通常使用.properties文件定义各语言的文本&#xff0c;里面可以用{0},{1},{2}表示待插入的变量值&#xff08;之所以用数字&#xff0c;不用%s、%d等占位符&#xff0c;是因为不同语言的语序不同&#xff09;。 用java.util.ResourceBundle类的Resourc…

javaWeb教务查询系统

一、简介 在教育管理领域&#xff0c;教务管理系统是一个至关重要的工具&#xff0c;它能够有效地协调学校、教师和学生之间的各种活动。我设计了一个基于JavaWeb的教务管理系统&#xff0c;该系统包括三个角色&#xff1a;管理员、教师和学生。管理员拥有课程管理、学生管理、…

深度理解文件操作

目录 文件 文件名&#xff1a; 标准流 文件指针 文件的打开和关闭 文件的顺序读写&#xff1a; 使用部分 文件的打开和关闭 文件 文件分两种&#xff0c;第一种是程序文件&#xff0c;后一种是数据文件。 程序文件&#xff1a;包括源程序文件&#xff08;后缀为.c&…

Web APIs 学习知识总结

渲染学成在线案例 html文件: <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-UA-Com…

聊聊k8s服务发现的优缺点

序 本文主要研究一下使用k8s服务发现的优缺点 spring cloud vs kubernetes 这里有张spring cloud与kubernetes的对比&#xff0c;如果将微服务部署到kubernetes上面&#xff0c;二者有不少功能是重复的&#xff0c;可否精简。 这里主要是讲述一下如果不使用独立的服务发现&am…

代码学习记录28----贪心算法

随想录日记part28 t i m e &#xff1a; time&#xff1a; time&#xff1a; 2024.03.26 主要内容&#xff1a;今天深入学习贪心算法&#xff0c;接下来是针对题目的讲解&#xff1a;1.柠檬水找零 &#xff1b;2. 根据身高重建队列&#xff1b;3.用最少数量的箭引爆气球 860.柠…

Jmeter压测实战:Jmeter二次开发之自定义函数

1 前言 Jmeter是Apache基金会下的一款应用场景非常广的压力测试工具&#xff0c;具备轻量、高扩展性、分布式等特性。Jmeter已支持实现随机数、计数器、时间戳、大小写转换、属性校验等多种函数&#xff0c;方便使用人员使用。如果在使用过程中存在和业务强耦合的常用功能函数…

数据结构与算法分析引论1

1.解决问题的算法有很多&#xff0c;但是在输入不同的情况下&#xff0c;不同算法之间的差异也很大&#xff0c;我们总是追求一个更快、更有效的方法。比如说普通的依次查找和二分查找&#xff0c;两者的差异就很大。我们使用大O表示法来表示算法的速度。依次查找就是O(n)&…

vs右键在浏览器中查看报错

vs右键在浏览器中查看报错Visual studio 右键在浏览器中查看报错HTTP错误500.30——ANCM进程内启动失败——.NET Core HTTP Error 500.30 - ANCM In-Process Start Failure - .NET Core HTTP Error 500.30 - ANCM In-Process Start Failure Common solutions to this issue: …

Android Studio 因JDK版本导致编译报错问题处理

一、报错问题提示 Cause: com/android/tools/idea/gradle/run/OutputBuildAction has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0 二、处理方…

论文阅读笔记——Rethinking Pointer Reasoning in Symbolic Execution

文章目录 前言Rethinking Pointer Reasoning in Symbolic Execution12.1、基本情况概述12.2、摘要12.3、引言12.4、方法12.4.1、基本版本12.4.1.1、内存加载和存储12.4.1.2、状态合并 12.4.2、改进12.4.2.1、地址范围选择12.4.2.2、内存清理12.4.2.3、符号化的未初始化内存12.4…

从汇编以及栈帧层面理解内联函数的原理

宏太复杂&#xff0c;所以弄出内联&#xff0c;内联适合小函数&#xff0c;把函数连到程序里面&#xff0c;这样就直接用&#xff0c;不需要调用&#xff0c;但是它占用空间。 C推荐 const和enum替代宏常量 inline去替代宏函数 宏缺点&#xff1a; 1、不能调试 2、没有类型安…