Morris,我想让你遍历我的二叉树!

本文介绍了二叉树普通遍历的空间复杂度问题,对比了Morris遍历的O(1)空间复杂度优势,并通过Python代码演示了Morris遍历的过程,包括节点连接和回调机制。
摘要由CSDN通过智能技术生成

我习惯用python来诠释算法代码,其一,python的代码相对简洁,不像c语言等复杂,使大家思路清晰。其二,简洁的代码我也省下不少时间,毕竟专业作业真是越来越多,哎。当然实际上肯定不是用python来实现,不如c语言的效率快,毕竟真实讲原理嘛。

看不懂可以参考B站up主视频来学习:点击跳转morris算法视频

为什么二叉树普通算法空间复杂度为O(n)?

          稍微了解一点二叉树的都知道二叉树的三种普通递归遍历(先序、中序、后续遍历),啊?你不知道,:点击任意门传送,对于新的学者来说,可能并不知道,这些遍历方法为什么会消耗内存,因为这些方法里似乎并没有任何的开辟空间的函数方法,对于刚学的我来说的时候亦是一样的,因为并不清楚栈的概念,甚至不清楚栈的存在,如果你暂时不想清除这一点,也就可以跳过了。
         我先创建一个伪代码方便于理解:

def 函数1(num):
	num-=1
	if num>0:
		函数1(num)
	print("执行了1次")
函数1(3)

图1-1为以上函数过程的解释:
Alt
                                                                                                              图 1-1
               压栈的操作本质上存储了某个函数的执行状态,从最后的函数依次执行完,也就是所谓的先进后出,后进先出的特点。
所以,递归函数调用搜索二叉树,每次遍历到下一个节点,其实栈中都有保存函数的递归记录,即为O(1)空间复杂度,这个消耗的内存是不小于单单记录节点信息的。

为什么morris可以做到空间复杂度为O(1)?

               空间的消耗来源于对于之前遍历过的节点的维护,方便使其跳转到原来的位置,但并不是说使其找到原来节点的位置就只有一一记录的方法,我们可以利用二叉树结尾端来指向之前的节点,当遍历到未节点时,发现为节点指向头节点,说明遍历到底了,此时当前节点就可以换个方向接着遍历了。
一颗二叉树:
在这里插入图片描述

morris遍历的过程

前面提到过要想回到原来节点,必须有记录操作,所以创建两个变量,一个代表当前节点的位置,第二个用来进行向下延申节点进行结尾与头节点的连接,或者是判定是不是第一次来到该节点。
假设cur为当前节点,MorrisRight为”判断“节点。
在这里插入图片描述                                                                                               图 1-2
这种算法就是合理的利用了未节点空余的接口,与头节点建立联系,达到回调的效果。
创建cur和morrisRight(mostRight)变量,cur代表当前节点,morisRight为判断变量。图1-3表示遍历判断过程
在这里插入图片描述
                                                                                                   图1-3

          开始cur为a点,a存在左端点b,找到b节点下最右下的端点,发现h指向None,则使得h.right=a,然后cur左移到b,然后重复以上操作,直到e点,就形成了图1-2。
          cur=e时,不存在左端点,则cur=cur.right(也就是图中的c),这样就实现了节点回调的效果。此时cur=c,接着下一次的循环开始,发现cur.left的最右下的端点指向cur(说明了cur的左子树遍历完了),让cur.left的右下端点的指针指向空(还原初始的状态),cur=cur.right(开始对cur的右子树遍历)。
          以上就是运行过程的介绍,可能不是很详细,那就结合以上给的视频链接观看吧

Morris遍历python代码实现

优雅python,永不过时!
结合注释快速理解:

def morrist(node):
    cur=node
    morristright=None     #创建维护节点
    while cur!=None:       #当cur=None,则表示遍历到树的最右下节点,所有节点遍历完成
        print(cur.data)
        morristright=cur.left
        if morristright:
            while morristright.right!=None and morristright.right!=cur:       #寻找左节点的右下节点
                morristright=morristright.right
            if morristright.right==cur:                #右下节点为cur说明该节点标记过,遍历过,遍历到了左子树的右下节点说明左子树遍历完成,开始遍历右子树(cur=cur.right)
                morristright.right=None       #还原未节点的None值
            else:
                morristright.right=cur
                cur=cur.left
                continue
        cur=cur.right                         #没有左节点或是左节点的右下指向头节点,指针都应该指向右子树

结束,欢迎大佬点评交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值