非递归方法实现二叉树前、中、后序遍历

文章目录

  • 非递归实现二叉树前、中、后序遍历
    • 一、非递归实现前序遍历
      • 1.思路
      • 2.代码
    • 二、非递归实现二叉树的中序遍历
      • 1.思路
      • 2.代码
    • 三、非递归实现二叉树的后序遍历
      • 1.思路
      • 2.代码


非递归实现二叉树前、中、后序遍历


一、非递归实现前序遍历

在这里插入图片描述

1.思路

  • 前序遍历的顺序是 :根——左——右

  • 模拟递归在栈上的执行过程

  • 用栈来实现

1.用cur代替root的移动,将当前cur压栈并打印

2.cur指向当前cur的左子树,cur.left压栈并打印,直到cur的左边遇到空为止

3.先序遍历时,根节点压栈先不着急取出,栈是先进后出的,先找根的左子树,后续会出栈来利用根节点找右子树,栈维护了根节点出现的顺序

4.当cur为空时,弹出栈顶结点,栈顶结点的左边是为空的cur,要利用栈顶结点来找他的右边

5.如果此时栈顶元素的右边也为空,该节点的根左右找完了,当前结点代表着上一个根结点的左树找完了

6.上一个根节点的根、左找完了,弹出栈顶元素(上一个结点),来找他的右边

  • 也就是说,先让cur来找根并打印,一直找下去,遇到空了找右边。当最小的左子树的根左右都找齐后,这个子树和它的上一级的根已经找到,需要开始找当前根的右边,形成循环。最后这个二叉树的左子树找齐后,开始找右子树。
  • 用两个while循环,小循环的条件是cur不为空,负责进栈,大循环嵌套小循环,小循环外负责出栈
  • 大循环的条件是:出栈结点的右边不为空,或者栈不为空

2.代码

    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
         if (root==null){
            return res;
        }
        TreeNode cur = root;//cur指向root
        Deque<TreeNode> stack = new LinkedList<>();

        while (cur != null || !stack.isEmpty()) {
            while (cur != null) {//cur不等于空,进栈并打印
                stack.push(cur);
               // System.out.print(cur.val + " ");
               res.add(cur.val);
                cur = cur.left;//先找左树所有的根
            }
            TreeNode top = stack.pop();//cur为空了,出栈找结点的右边
            cur = top.right;//cur指向结点的右边,如果cur不为空,进入大循环,再次进小循环入栈
            //如果cur==null,则判断栈空不空,栈不为空,进入大循环,不进小循环,只出栈
        }
        return res;
    }

二、非递归实现二叉树的中序遍历

在这里插入图片描述

1.思路

1.和上面的前序遍历类似,不过中序遍历打印的顺序是: 左——根——右

2.所以在小循环中,cur找到左树的根后,进栈时不打印,等出栈时再打印

3.也就是说,找到叶子结点后,叶子结点左边为空时,弹出叶子结点并打印(左、根)

4.找叶子结点的右边,右边为空时,说明左中右已找完,

5.此时左边已打印完,cur为空,出栈并打印根节点,利用根节点找右边的结点

  • 打印的位置与前序遍历不同

2.代码

    public List<Integer> inorderTraversal(TreeNode root) {
       List<Integer> res = new ArrayList<>();
         if (root==null){
            return res;
        }
        TreeNode cur = root;//cur指向root
        Deque<TreeNode> stack = new LinkedList<>();

        while (cur != null || !stack.isEmpty()) {
            while (cur != null) {//cur不等于空,进栈并打印
                stack.push(cur);
               // System.out.print(cur.val + " ");
               
                cur = cur.left;//先找左树所有的根
            }
            TreeNode top = stack.pop();//cur为空了,出栈找结点的右边
            res.add(top.val);
            cur = top.right;//cur指向结点的右边,如果cur不为空,进入大循环,再次进小循环入栈
            //如果cur==null,则判断栈空不空,栈不为空,进入大循环,不进小循环,只出栈
        }
   
        
        return res;
    }

三、非递归实现二叉树的后序遍历

在这里插入图片描述

1.思路

  • 后序遍历的具体思路类似,但是有不同的地方

  • 前序遍历中,找结点的右边要出栈找,维护出栈顺序,出栈的那一刻起,左边之前已经为空或者打印了,出栈取到结点找到右边,如果有结点新的结点会进栈,如果为空说明子树应该找完了,此时跟出栈的结点无关了

  • 中序遍历只是打印的位置不一样,前序和中序遍历,要看结点的右边,需要出栈来查看,出栈的目的是,根和左已经找完了,只需要取出来找右边就可以了,右边找完根据栈返回上一级

    1.后续遍历的顺序: 左——右——根

    2.因为根是最后打印的,先要看左节点,所以根节点先不能出栈,用peek取到 存的根节点,找根节点的右边

    3.右边为空时,打印栈顶的结点,弹出栈顶,cur为空,进入大循环,查看栈顶的右边,不为空,改变cur的指向

    4.出栈有要求,所以会造成peek元素过后,再次找到已经打印的结点

    5.所以在打印的时候还要判断是否打印过该节点

2.代码

    public void postorderNor(TreeNode root) {
        if (root == null) {
            return;
        }
        TreeNode cur = root;//cur指向root
        TreeNode prev = null;//记录打印过的结点
        Deque<TreeNode> stack = new LinkedList<>();

        while (cur != null || !stack.isEmpty()) {
            while (cur != null) {

                cur = cur.left;//先找左树所有的根
            }
            TreeNode top = stack.peek();//根节点不出栈,用peek取到根节点

            if (top.right==null||top.right ==prev ){//排除打印过的元素
                //左边找到了,右边为空,打印栈中的结点
                System.out.print(top.val+" ");
                stack.push(top);//打印完后弹出
                //此时cur为空
                prev = top;//记录打印过的结点

            }else {
                cur = top.right;//右边不为空,cur指向右边
            }
        }
    }

点击移步博客主页,欢迎光临~

偷cyk的图

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

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

相关文章

JVM离线分析-使用MAT分析dump堆文件

1. MAT&#xff08;Memory Analyzer Tool&#xff09;的介绍 官方介绍 The Eclipse Memory Analyzer is a fast and feature-rich Java heap analyzer that helps you find memory leaks and reduce memory consumption. Use the Memory Analyzer to analyze productive heap …

软件设计模式原则(二)开闭原则

继续讲解第二个重要的设计模式原则——开闭原则~ 一.定义 开闭原则&#xff0c;在面向对象编程领域中&#xff0c;规定“软件中的对象&#xff08;类&#xff0c;模块&#xff0c;函数等等&#xff09;应该对于扩展是开放的&#xff0c;但是对于修改是封闭的”&#xff0c;这意…

springboot中使用redis管理session

前言 使用软件&#xff1a; redis&#xff1a; linux版本下载 windows版本下载 安装redis 下载redis http://download.redis.io/releases/ 源码安装redis&#xff08;ubuntu&#xff09; #将指定版本的redis上传到服务器#解压 sudo tar -xzvf redis-6.2.4.tar.gzcd re…

牛客项目(五)-使用kafka实现发送系统通知

kafka入门以及与spring整合 Message.java import java.util.Date;public class Message {private int id;private int fromId;private int toId;private String conversationId;private String content;private int status;private Date createTime;public int getId() {retur…

Springboot搭建微服务案例之Eureka注册中心

一、父工程依赖管理 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org…

服务器经常被攻击的原因

很多中小型企业都是选择虚拟主机服务器&#xff0c;是把一个服务器分成很多个给很多企业一起共用&#xff0c;可能同一个 IP服务器上就有很多个不同企业的网站&#xff0c;这个时候如果跟你同一个IP服务器的网站遭到DDoS攻击&#xff0c;就很有可能会影响到你的网站也无法正常访…

学习笔记二十七:K8S控制器Statefulset入门到企业实战应用

这里写目录标题 Statefulset控制器&#xff1a;概念、原理解读Statefulset资源清单文件编写技巧查看定义Statefulset资源需要的字段查看statefulset.spec字段如何定义&#xff1f;查看statefulset的spec.template字段如何定义 Statefulset使用案例&#xff1a;部署web站点State…

apollo云实验:定速巡航场景仿真调试

定速巡航场景仿真调试 概述启动仿真环境仿真系统修改默认巡航速度 实验目的福利活动 主页传送门&#xff1a;&#x1f4c0; 传送 概述 自动驾驶汽车在实现落地应用前&#xff0c;需要经历大量的道路测试来验证算法的可行性和系统的稳定性&#xff0c;但道路测试存在成本高昂、…

webgl入门-基础三角形绘制

背景 最近工作上频繁接触webgl&#xff0c;因为不熟悉每每看到shader中的语法总感觉脑袋大&#xff0c;所以打算开始从零学习一下webgl&#xff0c;文章只做记录学习历程&#xff0c;那就直接开始吧&#xff01; 开始 可以配合着这个文章食用。 我还是对webgl有一些概念的&…

Java 8 新特性 Stream 的使用场景(不定期更新)

方便在写代码的过程中直接使用&#xff0c;好记性不如好文章&#xff0c;直接 CV 改了直接用。提高 办&#xff08;摸&#xff09;公&#xff08;鱼&#xff09;效&#xff08;时&#xff09;率&#xff08;间&#xff09;&#xff0c; 不然就直接问 GPT 也不是说不行。 只符合…

AI:52-基于深度学习的垃圾分类

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌本专栏包含以下学习方向: 机器学习、深度学…

WPF布局控件之DockPanel布局

前言&#xff1a;博主文章仅用于学习、研究和交流目的&#xff0c;不足和错误之处在所难免&#xff0c;希望大家能够批评指出&#xff0c;博主核实后马上更改。 概述&#xff1a; DockPanel 位置子控件基于子 Dock 属性&#xff0c;你有 4 个选项停靠&#xff0c;左 (默认) &…

接口自动化测试难点:数据库验证解决方案 百分之90人不知道

接口自动化中的数据库验证&#xff1a;确保数据的一致性和准确性 接口自动化测试是现代软件开发中不可或缺的一环&#xff0c;而数据库验证则是确保接口返回数据与数据库中的数据一致性的重要步骤。本文将介绍接口自动化中的数据库验证的原理、步骤以及示例代码&#xff0c;帮…

最新版星火官方搬运工具6.0,高级搬运,100%过原创,短视频上热门搬运软件黑科技【搬运脚本+使用技术教程】

软件介绍&#xff1a; 高级搬运&#xff0c;条条过原创 短视频暴力热门搬运黑科技 自研摄像头内录突破性技术6.0 无需任何繁琐准备工作安装即用 无需复杂售后培训看教程即可学会 直装直用自研技术更好卖 无需root 无需框架 更方便 无需xposed 无需vcam更安全 适配99%以…

SaveToDisk属性

大家好&#xff0c;才是真的好。 Domino Designer的帮助文档里面充满了宝藏&#xff0c;最近就发现一个notesitem对象的SaveToDisk属性&#xff0c;你可以设置它为false&#xff0c;这样&#xff0c;虽然文档保存了&#xff0c;但这个字段本身可以不用保存&#xff0c;不仅可以…

ROS分布式演练,多台设备进行通信的配置

1、概述 前面我们做的操作都是在单个设备上进行&#xff0c;也就是分别开启多个终端&#xff0c;在不同终端上启动节点等相关操作&#xff0c;这里我们使用两台设备来控制&#xff0c;一台虚拟机和一台无人车(使用VNC Viewer连上去&#xff0c;也可以看做一台Linux虚拟机) VNC…

初识FFmpeg

前言 无意间见到群里的小伙伴展示视频工具。功能比较多&#xff0c;包括视频编码修改&#xff0c;画质处理&#xff0c;比例处理、名称提取&#xff0c;剪辑、标题拆解。因此开始了FFmpeg学习。以下摘自百度百科的解释。 FFmpeg是一套可以用来记录、转换数字音频、视频&#xf…

【React】02.create-react-app基础操作

文章目录 当前以及未来的开发&#xff0c;一定是&#xff1a;组件化开发如何划分组件React的工程化/组件化开发create-react-app基础运用运用react常用版本一个React项目中&#xff0c;默认会安装 2023年最新珠峰React全家桶【react基础-进阶-项目-源码-淘系-面试题】 当前以及…

c++ Vector 学习

vevtor 是c 中自带得动态数组&#xff0c;dynamic array array can hold different values/objects of same type 可以装不同得类型或者对象 dynamic size can be changed at runtime 可以运行得时候改变 要使用的话&#xff0c;先引入 #include <vector> std::vector…

稳定性测试—fastboot和monkey区别

一、什么是稳定性测试 稳定性测试是指检验程序在一定时间内能否稳定地运行&#xff0c;在不同的场景下能否正常地工作的过程。主要目的是检测崩溃、内存泄漏、堆栈错误等缺陷。 二、Monkey 1.什么是Monkey 是一个命令行工具&#xff0c;通常在adb安卓调试运行&#xff0c;模…