二叉树遍历的非递归实现方法

二叉树遍历的非递归算法 非递归的算法主要采用的是循环出栈入栈来实现对二叉树的遍历,下面是过程分析 阅读详情

二叉树的遍历,通常分为前序、中序、后序和层序遍历。而前序、中序和后序遍历,我们一般刚开始接触的都是递归实现的方式,这种情况不再赘述,本文是主要介绍的是二叉树遍历的非递归实现方法。

首先,定义树节点的结构:

class TreeNode {
	int val;
	TreeNode left;
	TreeNode right;
	TreeNode(int x) { 
		val = x; 
	}
}

1.堆栈实现


递归说白了就是栈的调用,这里我们使用Stack来自己实现,用堆栈实现的空间复杂度为O(n)。

前序遍历:

public void preorderStack(TreeNode root) {
    if (root == null) {
        return ;
    }
    Stack<TreeNode> stack = new Stack<TreeNode> ();
    stack.push(root);
    while (!stack.isEmpty()) {
        TreeNode node = stack.pop();
        System.out.println(node.val);
        if (node.right != null) {
            stack.push(node.right);
        }
        if (node.left != null) {
            stack.push(node.left);
        }
    }
}
该方法每次处理一个root节点时,首先输出root的值,然后先将root的右子树入栈,再将root的左子树入栈,如果栈不为空,将栈顶元素赋值给root,循环该过程。

中序遍历:

public void inorderStack(TreeNode root) {
    if (root == null) {
        return;
    }
    Stack<TreeNode> stack = new Stack<TreeNode> ();
    TreeNode cur = root;
    while (!stack.isEmpty() || cur != null) {
        if (cur != null) {
            while (cur != null) {
            stack.push(cur);
            cur = cur.left;
            }
        } else {
            cur = stack.pop();
            System.out.println(cur.val);
            cur = cur.right;
        }
    }
}
该方法利用栈先进后出的特点,对于当前cur节点,依次将cur和cur的左子树入栈,这样会首先访问cur的左子树,然后访问cur。当cur为空的时候,我们取出栈顶的元素并输出该节点的值,然后将该节点的右节点赋值给cur,开始访问该节点的右子树。

后序遍历:

public void postorderStack(TreeNode root) {
    if (root == null) {
        return ;
    }
    Stack<TreeNode> stack = new Stack<TreeNode> ();
    stack.push(root);
    TreeNode pre = root;
    while (!stack.isEmpty()) {
        TreeNode cur = stack.peek();
        if ((cur.left == null && cur.right == null) || cur.left == pre || cur.right == pre) {
            System.out.println(stack.pop().val);
            pre = cur;
        } else {
            if (cur.right != null) {
                stack.push(cur.right);
            }
            if (cur.left != null) {
                stack.push(cur.left);
            } 
        }
    }
}

该方法利用pre来记录上一个访问的节点,如果当前节点cur为叶子节点,或者pre为cur的孩子节点,表明cur的值可以被输出,否则我们会把cur的右孩子和左孩子相继入栈。

2.Morris实现

Morris方法所使用的空间复杂度为O(1),对上述堆栈方法的O(n)空间复杂度有很大的改善,这里有一篇文章(http://www.cnblogs.com/AnnieKim/archive/2013/06/15/MorrisTraversal.html),对Moriis遍历讲得非常详细。这里我主要展示一下我的代码,并介绍一下我的Morris后序遍历方法。

前序遍历:

public void preorderMorris(TreeNode root) {
    if (root == null) {
        return;
    }
    TreeNode cur = root;
    while (cur != null) {
        if (cur.left != null) {
            TreeNode tmp = cur.left;
            while (tmp.right != null && tmp.right != cur) {
                tmp = tmp.right;
            }
            if (tmp.right == null) {
                System.out.println(cur.val);
                tmp.right = cur;
                cur = cur.left;
            } else {
                tmp.right = null;
                cur = cur.right;
            }
        } else {
            System.out.println(cur.val);
            cur = cur.right;
        }
    }
}

中序遍历:

public void inorderMorris(TreeNode root) {
    if (root == null) {
        return;
    }
    TreeNode cur = root;
    while (cur != null) {
        if (cur.left != null) {
            TreeNode tmp = cur.left;
            while (tmp.right != null && tmp.right != cur) {
                tmp = tmp.right;
            }
            if (tmp.right == null) {
                tmp.right = cur;
                cur = cur.left;
            } else {
                tmp.right = null;
                System.out.println(cur.val);
                cur = cur.right;
            }
        } else {
        	System.out.println(cur.val);
            cur = cur.right;
        }
    }
}
后序遍历:

public List<Integer> postorderMorris(TreeNode root) {
	List<Integer> list = new ArrayList<Integer> ();
    if (root == null) {
        return list;
    }
    TreeNode cur = root;
    while (cur != null) {
        if (cur.right != null) {
            TreeNode tmp = cur.right;
            while (tmp.left != null && tmp.left != cur) {
                tmp = tmp.left;
            }
            if (tmp.left == null) {
            	list.add(cur.val);
                tmp.left = cur;
                cur = cur.right;
            } else {
                tmp.left = null;
                cur = cur.left;
            }
        } else {
            list.add(cur.val);
            cur = cur.left;
        }
    }
    Collections.reverse(list);
    return list;
}

在引用的那篇文章的Morris后序遍历中,需要用到倒序输出的方法,这样无疑加大了代码量。这里,当最后遍历结果不是简单输出,而是保存在一个数组中时,我们可以利用先序遍历的思想,来得到后序遍历。由于先序遍历的访问顺序是:父节点-左孩子-右孩子,而后序遍历是:左孩子-右孩子-父节点,因此我们可以按照父节点-右孩子-左孩子的访问顺序来得到遍历的数组,然后将整个数组翻转,这样就能得到后序遍历的结果。其实这种思想不单单适用于Morris遍历,还适用于堆栈实现的遍历。



二叉树后序遍历的非递归实现方法 实现二叉树的后序遍历,不用递归,简单的有两种方法。方法一是通过在树节点设置一个标记,通过访问次数的标记Visit(初始化为0)来判断输出。void PostOrderTraversal(BinTree BT) { Stack S = CreateStack(); BinTree T = BT; while(T || !IsEmpty(S)){ T->visit 阅读详情

相关推荐

用非递归的方法实现二叉树中的层遍历,先序遍历,中序遍历和后序遍历

用栈实现二叉树中的层遍历,先序遍历,中序遍历和后序遍历

weixin_58368590的博客 457

数据结构——二叉树的非递归遍历

二叉树的非递归遍历,主要难点在于后序遍历。当出栈结点同时具有左右子树时需要判别遍历路经,确定是否已遍历右子树,遍历过右子树后再遍历根结点。

qq_42106610的博客 2310

vue微前端qiankun框架学习到项目实战,基座登录动态菜单及权限控制

技术无关,独立开发,独立部署,增量升级,独立运行,微前端的核心目标是将巨石应用拆解成若干可以自治的松耦合微应用。

前端开发工程师 9744

二叉树非递归遍历实现

二叉树遍历的非递归实现 基础知识 二叉树的遍历分为深度优先遍历(DFS)和广度优先遍历(BFS)。 深度优先遍历:尽可能地向左(或右)进行,在遇到第一个转折点,向左(或右)一步,然后再尽可能地向左(或右)发展。这一过程重复直到访问了所以节点。树的深度优先遍历一般有三种: VLR——前序遍历(根左右) LVR——中序遍历(左根右) LRV——后序遍历(左右根) 核心思路 遍历时一定要搞清楚一点就是,输出都是根节点(核心思想),因此不同的遍历方式仅仅是根节点的输出时机不同。 中序遍历:访问顺序为左根右。遇到节点

qq_38537501的博客 609

Springboot+Vue 实现鸿蒙商城管理系统开发实践

通过使用 Springboot 和 Vue 技术栈,我们成功实现了鸿蒙商城管理系统的开发。系统具备用户管理、商品管理、订单管理、库存管理和统计分析等功能,支持 Web 端和鸿蒙端的访问和操作。在开发过程中,我们充分利用了 Springboot 的快速开发优势和 Vue 的组件化开发特点,提高了开发效率和系统的可维护性。同时,通过与鸿蒙设备的集成,实现了多设备之间的数据交互和协同工作,提升了用户体验。

ZXJ_SXT的博客 1324

深入解析APS开源排程工具OptaPlanner:链式结构与移动优化

本文深入解析了开源APS排程工具OptaPlanner的核心机制,重点阐述了链式结构如何作为排程优化的“骨架”,通过单一`previous`变量隐式定义资源与顺序,从而简化建模。文章详细介绍了基于此结构的移动操作(如`ChainChangeMove`)如何驱动优化引擎探索解空间,并自动触发影子变量更新与分数计算,为构建高效、灵活的生产计划系统提供了实践指导。

keras9composer的博客 296

非递归实现二叉树遍历(附c++完整代码)

先序、中序和后序遍历过程:遍历过程中经过结点的路线一样,只是访问各结点的时机不同。 从图中可以看到,前序遍历在第一次遇见元素时输出,中序遍历在第二次遇见元素时输出,后序遍历在第三次遇见元素时输出。 非递归算法实现的基本思路:使用堆栈 一、前序遍历 1、递归实现 遍历过程为: 访问根结点; 先序遍历其左子树; 先序遍历其右子树。 void ProOrderTraverse(BiTree tre...

桑凯旋的博客 2万+

一文告诉你:如何在trae中编译运行GD32程序,并让AI帮你修改代码

本文详细介绍了如何将GD32程序如何用官方固件库构建出来,然后从Keil迁移到国产免费工具Trae,并利用AI进行代码修改的全过程。

水滴爬呀爬 2660

二叉树遍历的非递归实现(C语言)

内容: 编写程序,实现下述功能,并上机调试通过 (1)按中序顺序建立一棵二叉树; (2)用非递归方式遍历二叉树(先序),输出遍历序列。 【提示】采用二叉链表做存储结构,建立二叉树。借助于栈结构来实现二叉树遍历的非递归算法。 步骤: 1.算法分析: 根据题目需求,可知整个程序需要两个比较大的板块,第一个是要根据中序顺序建立一个二叉树,第二个是最重要的也是核心的是用非递归先序方式遍历二叉树。 首先来看第一步,要想完成第一步,首先需要了解到无论是扩展二...

qbyyds的博客 5719

Windows下Cppcheck静态测试全流程:从安装到生成HTML报告的避坑指南

本文详细介绍了在Windows平台下使用Cppcheck进行静态代码分析的全流程,包括环境搭建、插件配置、自动化脚本编写及HTML报告生成。重点解析了MISRA插件集成、常见问题排查以及性能优化技巧,帮助C/C++开发者高效提升代码质量。文章特别针对Windows环境下的路径处理、空格问题等细节提供了实用解决方案。

weixin_29313547的博客 199

SP贴图高效导入Maya:从材质设置到渲染优化的完整流程

本文详细解析了将Substance Painter(SP)贴图高效导入Maya并配合Arnold渲染器的完整工作流。针对SP贴图在Maya中常见的色彩、法线等问题,核心在于对齐两者的PBR“语言”,重点讲解了SP中正确的贴图导出设置(包括色彩空间)以及在Maya中连接aiStandardSurface材质、处理法线贴图、优化渲染的标准化流程,确保材质效果准确无误。

weixin_29201933的博客 554

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

前序遍历中,找结点的右边要出栈找,维护出栈顺序,出栈的那一刻起,左边之前已经为空或者打印了,出栈取到结点找到右边,如果有结点新的结点会进栈,如果为空说明子树应该找完了,此时跟出栈的结点无关了。中序遍历只是打印的位置不一样,前序和中序遍历,要看结点的右边,需要出栈来查看,出栈的目的是,根和左已经找完了,只需要取出来找右边就可以了,右边找完根据栈返回上一级。3.右边为空时,打印栈顶的结点,弹出栈顶,cur为空,进入大循环,查看栈顶的右边,不为空,改变cur的指向。前序遍历的顺序是 :根——左——右。

WengJM的博客 1128

Arduino智能小灯DIY:人体感应+光线感应+蓝牙控制全攻略(附完整代码)

本文提供了一份完整的Arduino智能小灯DIY制作指南。项目融合了人体感应、光线感应与蓝牙控制三大功能,通过详细的硬件清单、电路连接图、核心逻辑讲解及附带的完整代码,手把手教你打造一个能自动感知环境与人、并支持手机远程控制的智能照明装置,是入门智能家居和物联网开发的绝佳实践。

java5的博客 1093

用递归和非递归的方法实现二叉树遍历

用递归和非递归的方法实现二叉树遍历。

u011223173的博客 679

第4章--CANoe library开发 - 诊断功能

因为专栏要做的是汽车ECU自动化测试程序,测试的是ECU的诊断和刷新,因此就需要利用CANoe的接口,开发一些方便使用的诊断报文收发函数。

j187067046的博客 1396

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

C++实现二叉树前序中序后续遍历的非递归方法总结

前序中序相对简单,不废话,直接代码:

njustzj001的专栏 4843

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

使用递归和非递归方法实现二叉树的三种遍历

前序遍历:每个树的遍历顺序为:根节点→左节点→右节点。上图的前序遍历输出为:FCADBEHGM 中序遍历:每个树的遍历顺序为:左节点→根节点→右节点。上图的前序遍历输出为:ACBDFHEMG 后序遍历:每个树的遍历顺序为:左节点→右节点→根节点。上图的前序遍历输出为:ABDCHMGEF 1.前序遍历 递归法 /** * Definition for a binary tree node...

盛夏与微风 843

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

利用非递归方法实现二叉树的后序遍历

说了有空再写, 一直没写, 见谅。

认知 行动 坚持 7589

递归和非递归俩种方法实现二叉树的前序、中序、后续遍历

/* copyright@nciaebupt 转载请注明出处 题目:递归和非递归俩种方法实现二叉树的前序遍历 分析: 按照二叉树前序遍历的定义,无论是访问整棵树还是其子树,均应该遵循先访问根结点, 然后访问根结点的左子树,最后访问根结点的右子树的。 因为对于一棵树(子树)t,如果t 非空,访问完t 的根结点值后,就应该进入t 的左子树, 但此时必须将t 保存起来,以便访问完其左子树后,进入其右子树

nciaebupt 922

用非递归的方法实现对给定二叉树的 3 种遍历

其中BinTreeint flag;要求 3 个函数分别按照访问顺序打印出结点的内容,格式为一个空格跟着一个字符。此外,裁判程序中给出了堆栈的全套操作,可以直接调用。

c53972的博客 322

二叉树遍历 非递归 java_Java实现二叉树的前序、中序、后序、层序遍历(非递归方法)...

在上一篇博客中,实现了Java中二叉树的四种遍历方式的递归实现,接下来,在此实现Java中非递归实现二叉树的前序、中序、后序、层序遍历,在非递归实现中,借助了栈来帮助实现遍历。前序和中序比较类似,也简单一些,但是后序遍历需要两个栈来进行辅助,稍微复杂一些,层序遍历中借助了一个队列来进行实现。同样是那棵二叉树前序遍历:4 2 1 3 6 5 7 8 10中序遍历:1 2 3 4 5 6 7 8 10...

weixin_42570296的博客 183

二叉树遍历—非递归方法—C语言实现

二叉树的非递归遍历:先序、中序、后续、层序。 其中前三种用了栈来辅助存储结点,层序利用了队列来辅助存储结点。 后序较前面两种遍历稍微复杂点,因为根结点是最后输出的,所有根结点要访问到2次,在第二次访问时输出,需要做辅助标记。 为了简化问题,二叉树也简单的形同:ABC##DE###FG###    #代表空结点。 当然,为了和前面的知识点联系起来,stack和queue都是自己写的,没有用S...

小铅笔 1715

二叉树遍历的递归、非递归方法(前序、中序、后序,层序)——Java实现

1. 二叉树的前序遍历(深度优先遍历) 二叉树的节点定义 public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } } 递归实现: public class MyTest { static ArrayList<Integer> li...

一只特立独行的猪 417

二叉树3种遍历方法的递归和非递归实现

二叉数的遍历

sparrow学习博客 1245

利用非递归方法实现二叉树的先序遍历

#include #include #define N 7 using namespace std; typedef struct node { struct node *leftChild; struct node *rightChild; int data; }BiTreeNode, *BiTree; // 生成一个结点 BiTreeNode *create

认知 行动 坚持 8480

请用递归和非递归俩种方法实现二叉树的前序遍历。

//递归前序遍历 void pre_visit(TNode* root) { if (!root) return; cout data << ' '; pre_visit(root->left); pre_visit(root->right); } //非递归前序遍历 void pre_visit1(TNode* root) { if (!root) { cout << "空

Edwards_June的专栏 469
上一篇: 中文数字版atoi【Java实现】
下一篇: 【Docker】Docker1.3改动简介
低调de走过
博客等级 码龄17年 10粉丝 19原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值