【数据结构】二叉树的三种遍历(非递归讲解)

目录

1、前言

2、二叉树的非递归遍历

2.1、先序遍历

2.2、中序遍历

2.3、后序遍历


1、前言

学习二叉树的三种非递归遍历前,首先来了解一下递归序

递归序就是按照先序遍历的顺序,遇到的所有结点按顺序排列,重复的结点也必须记录。

我们可以发现递归序中每个结点都会遇到三次。

这是因为当进入某一结点时,对该结点进行第一次操作,然后调用其左孩子结点,等左孩子结点结束调用时会返回自己,此时就可以对自己进行第二次操作,然后再调用其右孩子结点,等左孩子结点结束调用时又会返回自己,此时就可以对自己进行第三次操作,因为不管怎样,调用完孩子结点后终究会返回到父结点。

直接给出结论:

递归序中第一次遇到该节点时打印结点,第二次第三次均不做任何操作,这就是先序遍历

递归序中第二次遇到该节点时打印结点,第一次第三次均不做任何操作,这就是中序遍历

递归序中第三次遇到该节点时打印结点,第一次第二次均不做任何操作,这就是后序遍历

关于递归序详细的讲解,可以看我之前写的一篇博客,里面有详细讲解,这里就不过多赘述:

【算法与数据结构】二叉树的三种遍历代码实现(上)—— 用递归序知识点讲解-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/133609612?spm=1001.2014.3001.5501

2、二叉树的非递归遍历

任何递归函数都可以改成非递归函数,因为递归函数不是什么玄学,只是递归时系统帮忙解决了压栈问题。那么不用递归方式的话只要自己手动进行压栈依然可以完成递归能够实现的功能。

有了上面递归序的知识点作为铺垫,就可以很好的理解非递归的实现了。

2.1、先序遍历

递归序中第一次遇到该节点时打印结点,第二次第三次均不做任何操作,这就是先序遍历

首先使用cur依次将二叉树所有左边界节点入栈,并且打印节点。当此时cur走到叶子节点后,将栈顶元素出栈,并让cur指向出栈元素的右孩子,继续进行左边界节点入栈操作。

    public List<Integer> preorderTraversal(TreeNode root) {List<Integer> list = new LinkedList<>();if(root == null) {return list;}Stack<TreeNode> stack = new Stack<>();TreeNode cur = root;while(cur != null || !stack.isEmpty()) {if(cur != null) {stack.push(cur);System.out.print(cur.val + " ");  //第一次遇到时进行打印cur = cur.left;} else {cur =  stack.pop();   //第二次遇到cur = cur.right;}}return list;}

2.2、中序遍历

递归序中第二次遇到该节点时打印结点,第一次第三次均不做任何操作,这就是中序遍历。 

首先使用cur依次将二叉树所有左边界节点入栈。当此时cur走到叶子节点后,将栈顶元素出栈后并打印,此时第二次遇到该元素。然后让cur指向出栈元素的右孩子,继续进行左边界节点入栈操作。

    public List<Integer> inorderTraversal(TreeNode root) {List<Integer> list = new LinkedList<>();if(root == null) {return list;}Stack<TreeNode> stack = new Stack<>();TreeNode cur = root;while(cur != null || !stack.isEmpty()) {if(cur != null) {stack.push(cur);   //第一次遇到cur = cur.left;} else {cur =  stack.pop();System.out.print(cur.val + " ");   //第二次遇到时进行打印cur = cur.right;}}return list;}

2.3、后序遍历

递归序中第三次遇到该节点时打印结点,第一次第二次均不做任何操作,这就是后序遍历

首先使用cur依次将二叉树所有左边界节点入栈。当此时cur走到叶子节点后,使用peek()查找出栈顶元素top(并非出栈)后并打印,然后判断top节点是否存在右孩子,当存在时则让cur指向top节点的右孩子,继续进行左边界节点入栈操作。当top不存在右孩子时则将栈顶元素出栈并打印栈顶元素,此时第三次遇到该元素。

    public List<Integer> postorderTraversal(TreeNode root) {List<Integer> list = new LinkedList<>();if(root == null) {return list;}Stack<TreeNode> stack = new Stack<>();TreeNode cur = root;TreeNode prev = null;while(cur != null || !stack.isEmpty()) {if(cur != null) {stack.push(cur);   //第一次遇到cur = cur.left;} else {TreeNode top = stack.peek();   //第二次遇到if(top.right != null && prev != top.right) {   //当该节点右子树不为空,并且之前没有去过右子树时cur = top.right;						} else {     //该节点右子树为空或者是已经去过一次右子树了top = stack.pop();System.out.print(cur.val + " ");   //第三次遇到时进行打印prev = top;}}}return list;}

博主推荐: 

【LeetCode力扣】单调栈解决Next Greater Number(下一个更大值)问题-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/136030138?spm=1001.2014.3001.5501 【数据结构】二叉搜索树的模拟实现-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/135910604?spm=1001.2014.3001.5501

 【LeetCode力扣】面试题 17.14. 最小K个数(top-k问题)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/135737266?spm=1001.2014.3001.5501

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

芯片设计方法学之--握手

1.面向对象 本文主要介绍握手的基本概念&#xff0c;读者可通过该篇文章对握手有个基本概念。也借此机会发表下自己对流水线中的握手反压的一些愚见。更深的理解可期待后续更新&#xff1b; 2. 握手简介 举个简单例子&#xff1b; 上图中sender拉高vld发送有效的数据给recei…

【芯片设计- RTL 数字逻辑设计入门 11.1 -- 状态机实现 移位运算与乘法 1】

文章目录 移位运算与乘法状态机简介SystemVerilog中的测试平台VCS 波形仿真 阻塞赋值和非阻塞赋值有限状态机&#xff08;FSM&#xff09;与无限状态机的区别 本篇文章接着上篇文章【芯片设计- RTL 数字逻辑设计入门 11 – 移位运算与乘法】 继续介绍&#xff0c;这里使用状态机…

【JS逆向八】逆向某企查网站的headers参数,并模拟生成 仅供学习

逆向日期&#xff1a;2024.02.07 使用工具&#xff1a;Node.js 加密方法&#xff1a;未知 / 标准库Hmac-SHA512 文章全程已做去敏处理&#xff01;&#xff01;&#xff01; 【需要做的可联系我】 可使用AES进行解密处理&#xff08;直接解密即可&#xff09;&#xff1a;AES加…

ChatGPT高效提问—prompt常见用法(续篇五)

ChatGPT高效提问—prompt常见用法&#xff08;续篇五&#xff09; 1.1 种子词 ​ 种子词&#xff08;seed word&#xff09;通常指的是在对话中使用的初始提示或关键词&#xff0c;用于引导ChatGPT生成相关回复。种子词可以是一个词、短语或句子&#xff0c;通常与对话的主题…

相机图像质量研究(9)常见问题总结:光学结构对成像的影响--工厂镜头组装

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…

机器学习中常用的性能度量—— ROC 和 AUC

什么是泛化能力&#xff1f; 通常我们用泛化能力来评判一个模型的好坏&#xff0c;通俗的说&#xff0c;泛化能力是指一个机器学期算法对新样本&#xff08;即模型没有见过的样本&#xff09;的举一反三的能力&#xff0c;也就是学以致用的能力。 举个例子&#xff0c;高三的…

【EEG信号处理】时频图与时频图的观察

非常快速和松散的介绍频谱和时频分析 当我们看到一个时频图时&#xff0c;我们应该考虑什么&#xff0c;应该有什么样的问题 什么是time-frequency plots 我们知道&#xff0c;左边是在时间维度上&#xff0c;根据电极的变化来绘制的折线图&#xff0c;他在时间维度上的&#…

单片机——FLASH(2)

文章目录 flash &#xff08;stm32f40x 41x的内存映射中区域详解&#xff09;flash写数据时 flash &#xff08;stm32f40x 41x的内存映射中区域详解&#xff09; Main memory 主存储区 放置代码和常数 System memory 系统存储区 方式bootloader代码 OTP区 一次性可编程区 选项…

【Git版本控制 04】标签管理

目录 一、创建标签 二、查看标签 三、推送标签 四、删除标签 一、创建标签 标签tag&#xff0c;是对某次 commit 的⼀个标识&#xff0c;相当于起了⼀个别名。 相较于难以记住的 commit id &#xff0c; tag 很好的解决这个问题&#xff0c;因为 tag ⼀定要给⼀个让⼈容易…

NLP_“预训练+微调大模型”模式和Prompt/Instruct模式的异同

文章目录 “预训练微调大模型”的模式以提示/指令模式直接使用大模型“预训练微调大模型”模式和Prompt/Instruct模式的异同小结 “预训练微调大模型”的模式 经过预训练的大模型所习得的语义信息和所蕴含的语言知识&#xff0c;很容易向下游任务迁移。NLP应用人员可以根据自己…

JavaScript基础第四天

JavaScript 基础第四天 今天我们学习js的函数&#xff0c;包括普通函数、匿名函数、箭头函数以及函数作用域。 1. 函数的初体验 1.1. 什么是函数 函数是 JavaScript 中的基本组件之一。一个函数是 JavaScript 过程一组执行任务或计算值的语句。要使用一个函数&#xff0c;你…

qnx log写入文件 简单实现

qnx log写入文件 简单实现 #ifndef __COMMON_LOG__ #define __COMMON_LOG__#include "fcntl.h" #include "pthread.h" #include "stdarg.h" #include "unistd.h" #include <stdio.h> #include <string.h>//#define _LOG_…