数据结构与算法(python):二叉树的遍历(Morris)

1、简介

1.1、what?

通常二叉树遍历的实现方法主要有两类:递归实现和迭代实现,具体可以参考:https://blog.csdn.net/weixin_41665360/article/details/88861801#63_87

递归实现代码简单,迭代实现效率更高。这里将介绍第三类二叉树遍历方法: M o r r i s Morris Morris 遍历

既然已经有两类遍历方法,为什么还要第三类方法呢?这种方法有什么特点呢?

1.2、How?

我们知道,在使用迭代的方法深度优先遍历二叉树时,通常需要栈来存储路径,通常空间复杂度为: O ( H ) O(H) O(H),在树高度特别高的情况下,算法会占用大量的存储空间。 M o r r i s Morris Morris 遍历方法正是为了解决这一问题而生,该算法空间复杂度为:O(1)

我们都知道,二叉树深度优先遍历,一个重要的思想是:回溯。要想实现回溯,算法必须知道自己走过的路径。那么如何只使用固定大小的空间还能清楚路径呢?

M o r r i s Morris Morris 遍历的构思非常巧妙。通过观察不难发现,每次算法回溯都是在左子树遍历完以后。 M o r r i s Morris Morris 利用左子树最后一个结点,将最后一个结点的 r i g h t right right 设置为根节点,这样在遍历完左子树以后,算法可以顺势转到根节点,实现回溯!

可以发现,算法并非通过避免记录路径来节省遍历空间,而是充分利用树结点未利用的空间 n o d e . r i g h t node.right node.right 来链接到根节点实现回溯。

这样又产生一个问题:为 n o d e . r i g h t node.right node.right 赋值会改变原来树的结构!因此,在回溯访问完结点后,需要把链接删除!


2、Python 实现 Morris 遍历

寻找左子树最右结点

2.1、Morris 先序遍历

def preorder(root):
	if not root: return
	p = root; prenode = None
	while p:
		if p.left:
			prenode = p.left
			while prenode.right and prenode.right != p:
				prenode = prenode.right
			if not prenode.right:			#建立链接方便回溯
				print(p.val)				#打印
				prenode.right = p
				p = p.left
				continue
			if prenode.right == p:
				prenode.right = None		#回溯完成删除多余链接
		if not p.left: print(p.val)			#打印
		p = p.right

2.2、Morris 中序遍历

def inorder(root):
	if not root: return
	p = root; prenode = None
	while p:
		if p.left:
			prenode = p.left
			while prenode.right and prenode.right != p:
				prenode = prenode.right
			if not prenode.right:			#建立链接方便回溯
				prenode.right = p
				p = p.left
				continue
			if prenode.right == p:
				print(p.val)				#打印
				prenode.right = None		#回溯完成删除多余链接
		if not p.left: print(p.val)			#打印
		p = p.right

2.3、Morris 后序遍历

def ReverseAndPrint(root):
	if not root: return
	node = root
	t = None
	while node:
		p = node.right
		node.right = t
		t = node
		node = p
	node = t
	t = None
	while node:
		p = node.right
		print(node.val)
		node.right = t
		t = node
		node = p
def postorder(root):
	if not root: return
	p = root; prenode = None
	while p:
		if p.left:
			prenode = p.left
			while prenode.right and prenode.right != p:
				prenode = prenode.right
			if not prenode.right:			#建立链接方便回溯
				prenode.right = p
				p = p.left
				continue
			else:							#prenode.right == p
				prenode.right = None		#回溯完成删除多余链接
				ReverseAndPrint(p.left)
		p = p.right
	ReverseAndPrint(root)
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值