Morris遍历【时间O(n),空间O(1)的二叉树遍历】

二叉树中序遍历的三种方法 题目描述: 给定一个二叉树的根节点root,返回它的中序遍历。 方法一:递归 思路与算法: 二叉树的中序遍历:按照访问左子树-根节点-右子树的方式遍历这棵树,而在访问左子树或者右子树的时候我们按照同样的方式遍历,直到遍历这棵树,而在访问左子树或者右子树的时候我们按照同样的方式遍历,直到遍历完整棵树。因此整个遍历过程天然具有递归性质,我们可以直接用递归函数来模拟这一过程。 定义inorder(root)表示当前遍历到root节点的答案,那么按照定义,我们只要递归调用inorder(root.left 阅读详情

一般来说,二叉树有两种遍历方式,一种方式是递归遍历,一种是基于栈的非递归方式。

  • 1°递归遍历,有时间复杂度O(n)O(n)O(n),空间复杂度平均O(logn)O(logn)O(logn),最坏情况下O(n)O(n)O(n)
  • 2°基于栈的非递归遍历,有时间复杂度O(n)O(n)O(n),空间复杂度O(h)O(h)O(h)

而有一种巧妙的方法可以在时间复杂度为O(n),空间复杂度为O(1)的情况下实现二叉树遍历。这种方法由 J. H. Morris 在 1979 年的论文「Traversing Binary Trees Simply and Cheaply」中首次提出,因此被称为 Morris 遍历。

一、先序遍历

算法

1.如果跟结点root的左孩子为空,则打印root结点,root结点迭代为root的右孩子结点(所以函数参数不要为了图快而引用传递)
否则,定义cur结点为根结点root左子树的最右下角的结点,接下来又有两种情况:
①cur结点的右孩子指针已经指向root时,将该指针置空,root结点迭代为root结点的右孩子
②cur结点的右孩子指针为空时,打印root结点值,将cur结点的右孩子指针指向root,root结点迭代为root结点的左孩子
2.重复过程1直至root结点迭代为NULL

代码实现
// Preorder traversal without recursion and without stack  
void morrisTraversalPreorder(node* root)  
{  
    while (root)  
    {  
        // If left child is null, print the current node data. Move to  
        // right child.  
        if (root->left == NULL)  
        {  
            cout<<root->data<<" ";  
            root = root->right;  
        }  
        else
        {  
            // Find inorder predecessor  
            node* current = root->left;  
            while (current->right && current->right != root)  
                current = current->right;  
  
            // If the right child of inorder predecessor already points to  
            // this node  
            if (current->right == root)  
            {  
                current->right = NULL;  
                root = root->right;  
            }  
  
            // If right child doesn't point to this node, then print this  
            // node and make right child point to this node  
            else
            {  
                cout<<root->data<<" ";  
                current->right = root;  
                root = root->left;  
            }  
        }  
    }  
}  

二、中序遍历

算法

1.初始化cur结点为root
2.当cur不空时,检查其是否有左孩子结点
3.如果cur无左孩子,打印cur,并将其cur迭代为cur的右孩子结点
如果cur有左孩子,找到cur左子树的最右下方的叶子结点,定义为mostright
此时又有两种情况
①mostright的右孩子指针为空,则让其指向cur,cur迭代为cur的左孩子结点
②mostright的右孩子指针指向cur时,将其置空,cur迭代为cur的右孩子结点
4.重复过程2,3,直至cur为null

代码实现
void Morris( Node* root)
{
	Node *cur, *mostright;
	if (root == NULL) return;
	cur = root;
	while (cur != NULL) {
		if (cur->left_node == NULL) {
			cout << cur->data << endl;
			cur = cur->right_node;
		}
		else {
			/* Find the previous  of cur */
			mostright = cur->left_node;
			while (mostright->right_node != NULL && mostright->right_node != cur)
				mostright = mostright->right_node;
			/* Make cur as the right child of itsprevious */
			if (mostright->right_node == NULL) {
				mostright->right_node = cur;
				cur = cur->left_node;
			}
			/* fix the right child of previous */
			else {
				mostright->right_node = NULL;
				cout << cur->data << endl;
				cur = cur->right_node;
			}
		}
	}
}

三、后序遍历

算法

后序遍历较为复杂,这里直接贴出算法原文。
在这里插入图片描述

代码实现

暂无

参考:geeksforgeeks论坛与edpresso

morris遍历详解(实现树的前中后序遍历) morris遍历详解(实现树的前中后序遍历) morris遍历介绍 morris遍历是二叉树遍历算法的至强算法,不同于递归,非递归(栈实现)的空间复杂度,morris遍历可以将非递归遍历中的树的深度的空间开销,降为O(1)。从而实现时间复杂度为O(n),而空间复杂度为O(1)的精妙算法。 morris遍历利用的是树的叶节点左右孩子为空,这一特性来实现空间开销的极度缩减。 morris遍历的... 阅读详情

相关推荐

手把手调试Android 14 ShellTransitions:用Log追踪ActiveTransition与Handler匹配过程

本文详细介绍了在Android 14中调试ShellTransitions机制的方法,重点通过Log追踪ActiveTransition与Handler的匹配过程。文章提供了关键日志点植入策略、Handler匹配机制解析及实战调试案例,帮助开发者解决窗口转场动画中的卡顿和错乱问题,提升系统动画性能。

weixin_42652674的博客 431

[杂谈] 13. O(1)空间的 Morris法遍历二叉树

文章目录1. 前言2. 中序遍历2.1 **步骤**2.2 **图示**2.3 **复杂度分析**3. 前序遍历3.1 **步骤**3.2 **图示**3.3 复杂度分析4. 后序遍历4.1 步骤4.2 图示4.3 复杂度分析 1. 前言 本文主要解决一个问题,如何实现二叉树的前中后序遍历,有两个要求: O(1)空间复杂度,即只能使用常数空间; 二叉树的形状不能被破坏(中间过程允许改变其...

Y-puyu 的博客 452

ZYNQ平台上基于PHY芯片的IEEE1588/PTP高效实现方案

本文详细解析了在Xilinx ZYNQ平台上,如何通过选用支持IEEE1588/PTP的专用PHY芯片(如RTL8211FS-VS-CG、DP83640)来实现高精度时间同步的高效方案。文章对比了PS端与PL端MAC连接的优劣,提供了从硬件选型、接口设计、Linux驱动适配到PTP协议栈配置与性能优化的完整实战指南,并总结了关键避坑经验,为工业网络、电力系统等需要纳秒级同步的应用提供了清晰、可靠的实施路径。

kkk56的博客 1091

O(1)空间复杂度遍历二叉树——Morris遍历

  在之前学习的二叉树遍历(前文传送门)当中,其时间复杂度均为O(1)\mathcal{O}(1)O(1),而空间复杂度为O(n)\mathcal{O}(n)O(n),其或是利用递归调用栈或是数据结构中的栈结构来完成对树中节点的多次访问,也就是利用了辅助空间来实现二叉树的遍历。 文章目录1. 实现思路2. 代码实现3. 分析推导3.1 Morris遍历的规律和与递归栈方式的对比3.2 Morris前序遍历3.3 Morris中序遍历3.4 Morris后序遍历 1. 实现思路 将当前所遍历到的节点记为cu

To the beyond and infinity! 876

Aloudata 荣登“数智技术系列榜单”和“数据智能服务商 TOP30”

持续助力各行业数智化先进企业突破数据管理技术瓶颈,以更加敏捷、精准和可靠的数据交付驱动企业业务创新与经营提效

Aloudata的博客 668

Windowns下Git环境配置-命令行方式

文章目录一、配置Git1.1 下载Git并安装1.2 配置本地Git用户名和邮箱1.3 注册GitHub二、生成本地公钥,放到GitHub上-SSH Key2.1 生成本地公钥命令2.2 查看生成的公钥2.3 在GitHub放上公钥并测试连通性三、创建项目实操四、可能出现的问题4.1.push不成功4.2.提示SSL的问题4.3.域名不能解析的问题4.4.如果github连接不上的问题 一、配置Git 1.1 下载Git并安装 Git官网 默认安装,根据需要修改安装路径 1.2 配置本地Git用户名和邮箱

学习工作笔记 1137

二叉树Morris遍历方法(时间复杂度O(n)空间复杂度O(1))

#include <iostream> #include <bits/stdc++.h> using namespace std; struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(...

zjwreal 654

从零搭建Arduino仿真开发环境:SimulIDE与IDE配置全攻略

本文详细介绍了如何从零搭建Arduino仿真开发环境,涵盖SimulIDE与Arduino IDE的配置全流程。通过仿真模拟环境,开发者可以零成本试错,快速验证电路设计和程序逻辑,特别适合初学者和便携开发需求。文章提供了软件安装、环境配置、项目实战及问题排查的完整指南,帮助读者高效掌握Arduino仿真开发技巧。

weixin_29284657的博客 524

有没有玩过空间复杂度O(1)的二叉树中序遍历

二叉树的前序遍历,时间复杂度为O(N),空间复杂度为O(1)

这是书生呀 1133

Autosar配置——导入DBC后配置SecOC同步报文和同步请求报文

在Autosar中,安全性是一个重要的考虑因素,而SecOC(Secure On-Board Communication)是一种用于保护通信数据完整性和安全性的安全机制。在上述示例中,我们配置了同步报文和同步请求报文的属性。接下来,我们需要在Autosar中配置同步报文和同步请求报文。同步报文用于在通信双方之间同步SecOC状态,而同步请求报文用于请求SecOC的状态信息。通过以上配置,我们成功地导入了DBC文件,并在Autosar系统中配置了SecOC同步报文和同步请求报文。希望以上信息对您有所帮助!

CyberSphinx的博客 649

YOLO + SubspaceAD:一张良品图,检出所有未知缺陷

当YOLO遇上子空间建模,工业质检正迎来从“见多识广”到“举一反三”的质变时刻。

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 500

Morris二叉树前中后序遍历,O(n)时间,O(1)空间,直接记忆背诵

记忆口诀:循环当前,左右到底,右子有无,当前左右,后前前中 后左尾头,右子反转,next开头,首尾相接,遍历反转 0)前中后代码框架 TreeNode *cur=rootr,*temp=nullptr; while(cur){ temp=cur->left; if(temp){ whi...

Lifelong Learning Pan 342

交通仿真软件:SUMO_(13).Python脚本与TraCI接口

通过TraCI接口,用户可以实现与SUMO仿真器的实时交互,获取和控制交通数据。本文档详细介绍了如何使用Python脚本与TraCI接口进行交互,包括基本的设置、数据获取和控制方法。此外,还展示了几个高级应用示例,如交通流优化、多代理系统、车辆路径规划和车辆行为模拟。这些示例可以帮助用户更好地理解如何利用TraCI接口进行复杂的交通仿真和分析。希望这些内容对您有所帮助,如果您有任何问题或需要进一步的帮助,请参考SUMO的官方文档或社区支持。

kkchenjj的博客 1004

Morris遍历详解——二叉树先序中序后序遍历( 时间复杂度O(N),空间复杂度O(1) )

Morris二叉树遍历: 来到当前的节点:Cur 如果Cur无左孩子,Cur向右移动 (Cur = Cur.right) 如果Cur有左孩子,找到Cur左子树上最右的节点,记为 mostright (1) 如果mostright的右指针为null,则让其右指针指向Cur,并使Cur向左移动 (Cur = Cur.left) (2) 如果mostright的右指针指向Cur,则让其右指针...

一只热爱游戏的猫咪 8160

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Morris遍历(二叉树遍历方式,时间复杂度O(N),额外空间复杂度O(1))

假设来到当前节点cur,开始时cur来到头节点位置、 1) 如果cur没有左孩子,cur向右移动(cur = cur.right) 2) 如果cur有左孩子,找到左子树上最右的节点mostRight: a.如果mostRight的右指针指向空,让其指向cur,然后cur向左移动(cur = cur.left) b.如果mostRgiht的右指针指向cur,让其指向null,然后cur向右移动(cur = cur.right) 3) cur为空时遍历停止 J...

weixin_44196561的博客 465

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

树的前中后序的Morris遍历

Morris遍历是一种用于二叉树遍历的算法,它可以在不使用栈或队列的情况下实现中序遍历。该算法的时间复杂度为O(n)空间复杂度为O(1)。前序和中序的遍历很想,只不过在打印(收集结点信息的时候不同),中序遍历是在当前结点的左节点为空(curr.left==null),或者当前结点已经被线索化(prev.right==curr)的时候进行打印,仔细观察前序遍历的过程,我们通过修改打印的顺序即可.前序遍历是在当前结点的左节点为空(curr.left==null),或者当前结点没有被线索化(prev.right=

qq_64580912的博客 2470

morris遍历

二叉树的遍历方式,无论是递归还是非递归的,都绕不过一个东西,叫额外空间复杂度O(H) (其中 H 为树高)。 因为二叉树遍历过程中只能向下查找孩子节点而无法回溯父结点,因此这些算法借助栈来保存要回溯的父节点(递归的实质是系统帮我们压栈,非递归的方式是 我们自己压栈),并且栈要保证至少能容纳下 H 个元素(比如遍历到叶子结点时回溯父节点,要保证其所有父节点在栈中)。 而morris遍历则能做到时间复杂度仍为 O(N) 的情况下额外空间复杂度只需 O(1) 。 morris遍历利用了二叉树 大量的空闲的空间。.

Mr_zhang66的博客 500

Morris遍历二叉树

Morris遍历二叉树 Morris遍历可以做到额外空间复杂度O(1),时间复杂度O(n)。 需要两个指针cur和mostringt cur为当前节点 1.若cur没有左孩子 cur=cur->right 2.若cur有左孩子,找到左孩子的最右节点记为mostringt 若mostringt->right= =NULL,mostringt->right=cur , cur=cur...

qq_43477927的博客 194

二叉树的Morris遍历

二叉树的Morris遍历Morris遍历程序示例:Morris遍历实现二叉树先中后序遍历先序遍历中序遍历后序遍历 Morris遍历 Morris遍历就是用来遍历二叉树的一种算法,并且能够满足时间复杂度为O(N),额外空间复杂度为O(1)。算法的大致流程如下:使用一个指针cur,从二叉树的根节点出发遍历二叉树。直至cur指向空。 判断cur是否有左子树: 若没有左子树,直接让cur往右走(cur = cur->right) 若有左子树,则找到左子树的最右结点。对最右结点进行判断 若最右结点的右孩子为

qq_36276431的博客 296

二叉树遍历系列02-Morris遍历

二叉树遍历系列02-Morris遍历 一、引言 Morris遍历是一种时间复杂度为O(N),空间复杂度为O(1)的二叉树遍历方法,Morris遍历是一种迭代遍历,Morris遍历不需要借助额外的栈空间,只需要进行普通的循环迭代即可完成整棵二叉树的遍历,因为Morris通过利用结点空指针,完成了遍历的转移(十分巧妙的想法) 二、递归序 在二叉树遍历系列01,中讲解了二叉树遍历的递归序,这是一个非常重要的概念,因为这可以帮助我们更好的理解Morris遍历在遍历过程中对先序序列和中序序列以及后序序列的加工(

西城风雨楼 936

二叉树之Morris遍历

二叉树的Morris遍历的核心思想+遍历流程+前、中、后序的实现

qq_40478662的博客 488

求二叉树的最小深度(普通+Morris遍历进阶)

求一棵二叉树的最小高度(所有叶节点中距离头节点最短的)

qq_45491549的博客 508

神级遍历——morris

morris遍历介绍 morris遍历是二叉树遍历算法的超强进阶算法,跟递归、非递归(栈实现)的空间复杂度,morris遍历可以将非递归遍历中的空间复杂度降为O(1)。从而实现时间复杂度为O(N),而空间复杂度为O(1)的精妙算法。 morris遍历利用的是树的叶节点左右孩子为空(树的大量空闲指针),实现空间开销的极限缩减。 morris遍历的实现原则 记作当前节点为cur。 如果cur无左...

god-jiang的博客 405

Morris遍历(值得学习的二叉树遍历方法)

Morris遍历 morris遍历是二叉树遍历算法的超强进阶算法,跟递归、非递归(栈实现)的空间复杂度, morris遍历可以将非递归遍历中的空间复杂度降为O(1)。从而实现时间复杂度为O(N),而空间复杂度为O(1)的精妙算法。 morris遍历利用的是树的叶节点左右孩子为空(树的大量空闲指针),实现空间开销的极限缩减。 Morris遍历的实现原则 记作当前节点为cur。 如果cur无左孩子,cur向右移动(cur=cur.right) 如果cur有左孩子,找到cur左子树上最右的节点,记为m

Codeoh的博客 877

(左程云)算法讲解124【扩展】Morris遍历

前置知识讲解017、讲解018 - 递归方式遍历二叉树、非递归方式遍历二叉树之前讲过的二叉树三种序的遍历不管是递归还是非递归的方式,时间复杂度为O(n),额外空间复杂度为O(树高)Morris遍历解决的问题二叉树三种序的遍历,时间复杂度为O(n),额外空间复杂度为O(1)核心在于利用二叉树自身的空闲指针大厂笔试、比赛时,一般不会用到大厂面试时,一道普通的二叉树题目,可以先给出普通解法,然后和面试官聊Morris遍历的解法,可以增加印象分(装逼用)

哀莫大于心死 888
上一篇: Java大数类BigInteger的应用:计算1到100的阶乘和
下一篇: 【Java学习笔记】assert断言
RealWeakCoder
博客等级 码龄7年 236粉丝 68原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值