数据结构--二叉树的遍历(非递归)

article/2025/9/22 15:59:35

我们已经对二叉树的基本概念有了一定的了解,也对它的递归版本的前、中、后序遍历掌握的很好了,那么接下来就要介绍二叉树中遍历的非递归版本
>【数据结构】二叉树详解< 先看本篇文章效果更佳哦

目录

  • 1、非递归遍历解析
  • 2、前序遍历(非递归)
  • 3、中序遍历(非递归)
  • 4、后序遍历(非递归)

1、非递归遍历解析

我们知道深度优先遍历是需要用到栈的
在前序遍历的递归的写法中我们是将树分为 根【左子树的前序】【右子树的前序】 这样的视角来进行的,貌似在递归写法中我们没有用到栈,但实际上是在递归调用的时候使用了调用栈进行回溯了
在这里插入图片描述
可是在我们非递归的视角中是没有办法使用调用栈来进行回溯,所以我们要 手动的构建一个栈 来进行回溯操作

2、前序遍历(非递归)

非递归的前序遍历就是在每个结点第一次被访问到的时候进行打印,下图中红色的线就代表第一次访问某一个结点,紫色的线就是访问所有结点的完整路径

注意:叶子结点或只有一个孩子的结点,在访问时即使孩子为 null 也要对其左右孩子进行访问

在这里插入图片描述

就好比是有 4 条线依次往左走,最后就有了我们的前序序列 A B C D E F
那么怎么实现这 4 条线呢? 其实就是进行遍历,一直朝根结点的左孩子遍历直到遇到 null

TreeNode cur = root;while (cur != null) {打印(cur.val);cur = cur.left;
}

这样就可以一直向左进行遍历,但是此时会有一个问题:假如第 1 条线向左走遇到 null 了,那么怎么继续走第 2 条线呢?
在这里插入图片描述
这时候我们就需要用到回溯的,我们先走第 1 条线,遇到 null 则证明 C 的左子树已经访问完,所以要按照先访问 C 的右子树,紧接着访问 B 的右子树,然后访问 A 的右子树的顺序进行,这里就需要使用到栈来为我们进行回溯操作了
所以我们的想法就是在遍历结点的同时将该结点入栈,当一条线 走完之后就取出栈顶元素,然后像栈顶元素的右边进行遍历

TreeNode cur = root;
while(cur != null || 栈不为空) {while (cur != null) {打印(cur.val);入栈(cur);cur = cur.left;}//此时已经一条线走到底了top = 栈顶元素;cur = cur.right;	//还需开启一个循环来继续走下一条线
}

简单的对前两条线的遍历进行图解
在这里插入图片描述
其实就是当一条线走完后取出栈顶元素并访问其右孩子,然后继续之前的操作
完整代码

public static void preOrder(TreeNode root) {Deque<TreeNode> stack = new LinkedList<>();TreeNode cur = root;while (cur != null || !stack.isEmpty()) {while (cur != null) {System.out.printf("%c ", cur.val);stack.push(cur);	//入栈curcur = cur.left;}TreeNode top = stack.pop();		//取出栈顶元素cur = top.right;}}

3、中序遍历(非递归)

有了前序遍历的思想和基础,那么对于中序遍历来说就好理解了很多
前序遍历是第一次访问结点的时候进行打印输出,那么中序遍历就是在第二次访问该结点的时候进行打印输出
图中红色的线就是第二次访问结点的情况
在这里插入图片描述
那么什么时候是第二次经过结点呢?
第一次经过某结点是向左遍历时访问的结点是第一次经过该结点,那么第二次经过该结点就是从它的左孩子回来时经过就是第二次经过,也就是说当该元素从栈中弹出时就是第二次经过

TreeNode cur = root;while (cur != null) {入栈(cur);cur = cur.left;
}top = 栈顶元素;	//此时为第二次经过该结点

有了这个思路那我们就可以很快的写出中序遍历的非递归代码
完整代码

public static void inorder(TreeNode root){Deque<TreeNode> stack = new LinkedList<>();TreeNode cur = root;while (cur != null || !stack.isEmpty()){while (cur != null){stack.push(cur);cur = cur.left;}TreeNode top = stack.pop();		//第二次经过该结点System.out.printf("%c ", top.val);		//马上打印该结点cur = top.right;	//继续向右走}}

4、后序遍历(非递归)

后序遍历相较于前序和中序遍历来说考虑的方面较多一些
后序遍历的非递归视角就是第三次访问该结点时进行打印输出
图中红色的线就是第三次访问该结点的情况
在这里插入图片描述

但是在中序遍历的基础上,如果第二次访问将结点弹出栈后,再从该结点的右孩子回来时是第三次访问,但是结点已经被弹出栈了,所以会无法第三次访问结点
在这里插入图片描述
所以我们先在要着手解决一个问题:不要在第二次访问结点时将结点弹出栈

我们将 top = stack.pop() 变为 top = stack.peek()

并且我们就应该区分一下什么时候是第二次经过该结点,什么时候是第三次经过

第一次经过结点(就是从他的双亲过来时的情况)
第二次经过结点(就是从他的左孩子过来的情况)
第三次经过结点(就是从他的右孩子过来的情况)

那么就会有以下几种情况:
1.该结点的右孩子为空的情况,虽然从左孩子过来后是第二次经过该结点,但因为没有右孩子,就没有必要去访问它的右孩子,那么也就可以看作是第三次经过该结点
在这里插入图片描述
2.如果该结点的右孩子就是上一个访问过的结点,那么必然是从它右孩子过来的,就一定是第三次访问该结点
在这里插入图片描述
3.剩下的情况就证明不是第三次访问该结点,所以就像中序遍历一样,继续向栈顶元素的
完整代码

 public static void postorder(TreeNode root) {Deque<TreeNode> stack = new LinkedList<>();TreeNode cur = root;TreeNode last = null;	//用来记录上一个被访问的结点while (cur != null || !stack.isEmpty()) {while (cur != null) {stack.push(cur);cur = cur.left;}TreeNode top = stack.peek();	//第二次访问,只查看栈顶元素但不弹出if (top.right == null) {	//右孩子为空直接视为第三次访问System.out.printf("%c ", top.val);last = top;stack.pop();	//第三次访问,弹出栈顶元素} else if (top.right == last) {		//右孩子就是上一个被访问的结点就是第三次访问System.out.printf("%c ", top.val);last = top;stack.pop();	//第三次访问,弹出栈顶元素} else {	//否则就像右孩子方向走cur = top.right;}}}

http://chatgpt.dhexx.cn/article/aQxYy4Xh.shtml

相关文章

二叉树的非递归遍历 C语言版

文章作者&#xff1a;Slyar 文章来源&#xff1a;Slyar Home (www.slyar.com) 转载请注明&#xff0c;谢谢合作。 上周数据结构课在讲二叉树的遍历&#xff0c;老师只讲递归算法&#xff0c;没有什么技术含量&#xff0c;遂自己琢磨非递归算法实现... 前序遍历:先访问根节点&…

二叉树非递归遍历

1. 遍历一棵树 前、中、后序遍历的路径实际是相同的&#xff0c;都是以如上路径去游历。 前、中、后序访问的结果不同&#xff0c;实际是访问节点的时机不同&#xff1a; 前序&#xff1a;一遇到节点就去访问 中序&#xff1a;访问完左树再去访问 后序&#xff1a;访问完右子…

C语言数据结构七:二叉树非递归遍历

二叉树的非递归遍历&#xff0c;必须借助栈的辅助。必须采用栈的这种先进后出的特性。 算法实现思路&#xff1a; 我们先将根节点压入栈中。然后往外弹出元素。直到栈中元素弹完为止。1、将根节点压入栈中。&#xff08;但是压入栈中&#xff0c;并不知简单的将根节点压入栈中…

二叉树非递归遍历(先序、中序、后序)

首先是一个二叉树结构&#xff1a; class TreeNode{public int value;public TreeNode left;public TreeNode right;public TreeNode(){}public TreeNode(int v){valuev;} 非递归的二叉树遍历需要用到栈的先进后出。 先序遍历 步骤&#xff1a; 1、首先定义一个当前正在检索…

二叉树非递归遍历(c语言)

结果如下图&#xff1a; #号代表NULL&#xff0c;此时没有节点 一、在c语言中进行二叉树的非递归遍历需要用到栈&#xff0c;而在c语言中没有直接调用栈的接口&#xff0c;所以在实现非递归遍历时需要先实现一个栈&#xff0c;需要用到出栈&#xff0c;入栈&#xff0c;栈顶元…

二叉树非递归遍历实现(Java)

首先理解一下二叉树节点结构。left指向左节点&#xff0c;right指向右节点&#xff0c;val为节点中的值。 class TreeNode {int val;TreeNode left;TreeNode right;public TreeNode(int x) {val x;}} 先序遍历 //非递归先序遍历&#xff08;需一个辅助栈&#xff0c;顺序为根…

二叉树遍历的一些非递归算法

二叉树的非递归算法因为涉及到栈和队列&#xff0c;所以写的时候总是受到伪代码的干扰&#xff0c;要完整的补全栈和队列的结构有些麻烦&#xff0c;这里借鉴了一些大佬的思想&#xff0c;发现可以直接在树中模拟栈和队列的存在&#xff0c;这给非递归的完整代码带来了很大的便…

三种非递归遍历二叉树的方法

就以这个树为例&#xff0c;来讲讲二叉树的非递归遍历。 先序遍历&#xff1a; 先序遍历结果为3 4 6 5 8 9&#xff0c;就拿树的左枝为例&#xff0c;3是根&#xff0c;打印&#xff0c;4是3的左孩子&#xff0c;打印&#xff0c;6是4的左孩子&#xff0c;打印&#xff0c;6的…

二叉树的非递归遍历

目录 一.前序遍历&#xff08;根左右&#xff09; 1.思路图解 2.代码 二.中序遍历&#xff08;左根右&#xff09; 1.思路图解 2.代码 三.后序遍历&#xff08;左右根&#xff09; 1.思路图解 2.代码 四.层序遍历 1.思路图解 2.代码 一.前序遍历&#xff08;根左右…

smile——Java机器学习引擎

介绍 Smile&#xff08;统计机器智能和学习引擎&#xff09;是一个基于Java和Scala的快速、全面的机器学习、NLP、线性代数、图形、插值和可视化系统。 凭借先进的数据结构和算法&#xff0c;Smile提供了最先进的性能。Smile有很好的文档记录&#xff0c;请查看项目网站以获取…

Java机器学习库(Java ML)(一、分类)

本文章翻译至Java ML技术文档classification.pdf&#xff0c;代码部分是参考该文档使用IDEA编写&#xff0c;同时加入了运行结果。 分类 本文介绍与分类相关的功能。 该文章假设您已熟悉Java ML的基础知识&#xff0c;如入门教程中所述&#xff08;http://java-ml.sourcefor…

目前流行的、强大的基于Java的机器学习开发库精选

图片来源: Mindfire Solutions 现如今&#xff0c;拥有深度学习和机器学习领域的技术是科技界的趋势之一&#xff0c;并且企业则希望雇佣一些拥有良好的机器学习知识背景的程序开发工程师。本文将介绍一些目前流行的、强大的基于Java的机器学习库&#xff0c;希望给大家带来帮助…

JAVA 人工神经网络实现,机器学习,人工智能

人工智能&#xff08;AI&#xff09; 、机器学习&#xff08;ML&#xff09;、深度学习&#xff08;DL&#xff09;、神经网络&#xff08;CNN&#xff09; IT技术圈的人怼这些词汇大家都一定耳熟能详了&#xff0c;可能圈外的也不陌生&#xff0c;但是作为一个作为一个“攻城…

机器学习java_如何开始使用Java机器学习

机器学习java 什么是开始使用Java机器学习的最佳工具&#xff1f; 他们已经存在了一段时间&#xff0c;但如今看来&#xff0c;每个人都在谈论人工智能和机器学习。 对于科学家和研究人员而言&#xff0c;它已经不再是秘密&#xff0c;几乎可以在任何新兴技术中实现。 在下面…

谁说搞Java的不能玩机器学习?

简介 机器学习在全球范围内越来越受欢迎和使用。 它已经彻底改变了某些应用程序的构建方式&#xff0c;并且可能会继续成为我们日常生活中一个巨大的&#xff08;并且正在增加的&#xff09;部分。没有什么包装且机器学习并不简单。 它对许多人来说似乎非常复杂并常常令人生畏…

基于 Java 机器学习自学笔记 (第51-53天:kNN)

注意&#xff1a;本篇为50天后的Java自学笔记扩充&#xff0c;内容不再是基础数据结构内容而是机器学习中的各种经典算法。这部分博客更侧重与笔记以方便自己的理解&#xff0c;自我知识的输出明显减少&#xff0c;若有错误欢迎指正&#xff01; 目录 一、关于数据集及其导入…

基于 Java 机器学习自学笔记 (第66至68天:主动学习之ALEC)

注意&#xff1a;本篇为50天后的Java自学笔记扩充&#xff0c;内容不再是基础数据结构内容而是机器学习中的各种经典算法。这部分博客更侧重于笔记以方便自己的理解&#xff0c;自我知识的输出明显减少&#xff0c;若有错误欢迎指正&#xff01; 目录 前言 一、关于学习的分类…

超全!基于Java的机器学习项目、环境、库...

https://yq.aliyun.com/articles/278837?utm_sourcetuicool&utm_mediumreferral 摘要&#xff1a; 你是一名希望开始或者正在学习机器学习的Java程序员吗&#xff1f; 利用机器学习编写程序是最佳的学习方式。你可以从头开始编写算法&#xff0c;但是利用现有的开源库&am…

结合Java和机器学习技术,如何驾驭大数据提升业务效率和竞争力?

随着大数据的不断增长和发展&#xff0c;越来越多的企业和组织开始关注如何利用大数据来提高业务效率和竞争力。在大数据分析领域&#xff0c;Java和机器学习技术是两个非常重要的方向。本文将介绍这两个技术的基本概念、应用场景和发展趋势&#xff0c;并重点探讨如何结合Java…

25个JAVA 机器学习工具包

本列表总结了25个Java机器学习工具&库&#xff1a; 1. Weka集成了数据挖掘工作的机器学习算法。这些算法可以直接应用于一个数据集上或者你可以自己编写代码来调用。Weka包括一系列的工具&#xff0c;如数据预处理、分类、回归、聚类、关联规则以及可视化。 2.Massive Onli…