二叉树非递归遍历

article/2025/9/22 16:13:04

1. 遍历一棵树

前、中、后序遍历的路径实际是相同的,都是以如上路径去游历。

前、中、后序访问的结果不同,实际是访问节点的时机不同:

  • 前序:一遇到节点就去访问

  • 中序:访问完左树再去访问

  • 后序:访问完右子树再去访问

如下是B节点的前、中、后序访问时机
image-20220729114001774

2. 非递归遍历

2.1 理解

之前的递归遍历,将一棵树看成一个对称结构:左子树右子树,借助递归函数,可以进入左右子树进行访问;

但如果想在当前函数内进行迭代访问,之前的左右子问题的方式就很难实现了。

这里我们不妨再看看这个遍历的路径图:

首先沿着最左侧向下走过A-B-D

然后向上,走D的右子树、B的右子树、A的右子树,走完A的右子树回来就代表遍历结束了

这里访问右子树就可以看成是一个子问题——访问以右节点为根的另一棵树,重新回到最一开始;

可以发现左侧节点第一次走到的顺序是从上至下:A-B-D,下一次遇到访问右子树的顺序又是D-B-A,恰好相反,因此可以用的结构,从左侧走的时候先把节点依次从上至下存起来,当遍历到底,遇到空的时候再取出栈顶的节点,通过这个节点去访问它的右树;

同时凭借着栈的结构,当进入右树,走到右树的节点,依然入此栈,当右树走完回来,右树所有入栈的节点也都已经取出,又只剩下了之前主干上的节点,还可继续主线逻辑,与递归方式的逻辑相似——不管递归出去的逻辑多复杂,完成了分支任务回来,我的主线任务还要正常进行。

2.2 实现

注:以下只提供了非递归游历整棵树的方法,前、中、后序访问节点的时机未写入,具体见后。

变量定义:

image-20220729200149914

实现:

  1. 遍历最左侧节点,同时将他们依次入栈

    image-20220729195501313

  2. 开始取栈中元素

    image-20220729200734626

  3. 通过此节点访问它的右树

    image-20220729203750012
  4. 遍历结束的判断

    • 栈中元素取完——栈空
    • 同时当前的根节点对应一棵空树
    • 仅栈空,对应上图中的根节点A访问完后,
      但A节点还有右树,while判断时,cur是右树的根C
      接下来访问C和它的左树、F和它的左树,当访问完Fcur指向F的右—null
      此时栈空,cur == null,同时遍历也结束了。
    image-20220729204752809
  5. 子树为空的情况(返回主干问题):

    跳过当前树的遍历,从栈中取下一个节点

    当前逻辑刚好可以实现

    image-20220729204929251

3. 前、中、后序遍历

前、中、后序遍历唯一的区别就是访问节点的时机不同

每个节点可以看成是有三次被经过:到达初遇,从左边回来再遇,遍历完右子树再遇,

这三次相遇恰好就对应前、中、后序的访问时机,

只需在迭代逻辑中找到这三次相遇的对应部分进行访问,即可完成前、中、后序遍历。

image-20220729114001774

3.1 前序遍历

访问时机:第一次碰到,也就是左侧遍历要入栈的时候

image-20220729205541436

此时访问,进行入栈即可。

vector<int> preorderTraversal(TreeNode* root)
{vector<int> v;//存储访问出元素stack<TreeNode*> st;//栈——临时储存节点TreeNode* cur = root;//用于游历整棵树的指针while (!st.empty() || cur){//遍历当前树的所有最左侧节点while (cur){v.push_back(cur->val);st.push(cur);cur = cur->left;}//取出栈顶节点TreeNode* tmp = st.top();st.pop();//前序遍历右树cur = tmp->right;//更新root为栈顶节点的右树}return v;
}

3.2 中序遍历

访问时机:左侧节点访问已完成,节点出栈,马上要进入右树进行访问的时候

image-20220729210309210

此时访问,进行入栈即可。

vector<int> inorderTraversal(TreeNode* root)
{vector<int> v;//存储访问出元素stack<TreeNode*> st;//栈——临时储存节点TreeNode* cur = root;//用于游历整棵树的指针while (!st.empty() || cur){//遍历当前树的所有最左侧节点while (cur){st.push(cur);cur = cur->left;}//取出栈顶节点TreeNode* tmp = st.top();st.pop();v.push_back(cur->val);//前序遍历右树cur = tmp->right;//更新root为栈顶节点的右树}return v;
}

3.3 后序遍历

在整棵右树访问完成,再次回到这个节点的时候进行访问

由于访问右树是一个多层的迭代遍历,无法在这个单次的代码上直接找到访问的位置

观察后,右子树进行后序遍历的最后一个访问的节点是右树的根节点,访问完这个节点的下一个节点就是当前要访问的节点

image-20220729114001774

所以每次访问完一个节点,都将这个节点进行记录,节点要出栈都先判断栈顶节点对应的右节点是否为已记录节点

  • 若是,则出栈并进行访问,同时更新用于记录的节点,此时右树无需访问,直接访问下一个栈顶元素
  • 否则说明当前是②的位置,先不出栈,先访问右树,右树回来再出栈

**特殊情况:**当右树为空,这个节点也要访问

image-20220729221650278

如访问B的右树完时候,prev是D,但此时B也得进行访问,所以右树为空也要加入出栈访问的判断条件

image-20220729222652600

vector<int> postorderTraversal(TreeNode* root)
{vector<int> v;//存储访问出元素stack<TreeNode*> st;//栈——临时储存节点TreeNode* cur = root;//用于游历整棵树的指针TreeNode* prev = nullptr;while (!st.empty() || cur){//遍历当前树的所有最左侧节点while (cur){st.push(cur);cur = cur->left;}TreeNode* tmp = st.top();if (tmp->right == prev || tmp->right == nullptr){st.pop();v.push_back(tmp->val);prev = tmp;cur = nullptr;//下一次循环直接当空树访问下一个栈中节点}else{cur = tmp->right;//更新root为栈顶节点的右树}}return v;
}

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

相关文章

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…

7个最好的Java机器学习开发库

IT派 - {技术青年圈} 持续关注互联网、区块链、人工智能领域 摘要&#xff1a; 本文将介绍一些目前流行的、强大的基于Java的机器学习库。 图片来源: Mindfire Solutions 摘要&#xff1a;现如今&#xff0c;拥有深度学习和机器学习领域的技术是科技界的趋势之一&#xff0c;并…

基于 Java 机器学习自学笔记 (第71-73天:BP神经网络)

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