2024.4.8Morris中序遍历(线索二叉树)学习

news2025/9/22 0:28:18

这次博主在学习完知识点和代码之后,准备对这个知识重新进行整理总结。站在一个初学者的角度来看待这个知识点,在他人的讲解基础上加一点点自己的理解,并记录下来。以加深自己的理解,并且希望能够帮助到你。博主是一个初学者,若有不对请友善指出,大家一起学习进步。

一、知识点讲解

这里简单地进行说明。

1.为什么使用Morris中序遍历

树的递归使用的是栈这个数据结构来存储节点,以达到记录前驱节点的目的。而过多的内容很可能导致栈溢出。为了压缩空间(降低空间复杂度),所以我们使用Morris中序遍历,能够将空复降至O(1)。(结尾学习视频有更详细的原理解释)

2.什么是Morris中序遍历

既然递归中使用栈的原因是想记录前驱节点,那么我们只要达到记录前驱节点的目的即可不使用栈。

首先,它的本质还是中序遍历。

正常的中序遍历,在“递”左子树时是可以直接通过左指针到达,但是在“归”根节点的时候是没有办法直接到达的(右子树只用“递”,不用“归”)。而“归”的时候均是到达叶子节点才“归”,则可以充分利用叶子节点的左右空指针,将右空指针指向根节点,这样就可以直接“归”到根节点。

其中,为什么是右空节点呢?博主认为,因为根节点是叶子节点的后继节点,而中序遍历遍历完本节点下一个就遍历右节点,所以用叶子节点的右空节点指向根节点。

下面结合图进行理解:

0861f12048d748a8923dc2938a61d921.jpeg

其中,序号是按照中序遍历的顺序编号的,方便大家观看。

而红色的线就是我们需要增加的指针,称为线索(也是线索二叉树的由来)。

基本原理理解了,那我们就来看看代码是什么实现的。

二、代码及分析

1.实现代码

代码参考文章末尾学习视频。博主为代码添加了部分注释:

from typing import Optional

# Definition for a binary tree node.
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
class Solution:
    def MorrisInorderTraversal(self, root: Optional[TreeNode]):
        # 本质是中序遍历
        cur = root
        # 遍历节点
        while cur:
            # 没有左子树
            # 当前节点就没有中序遍历前驱节点,直接进入右边
            if not cur.left:
                cur = cur.right
            # 有左子树
            # 找cur的中序遍历前驱节点
            # 通俗讲,前驱在左节点最右边
            else:
                pre = cur.left  # 左节点
                # 到最右边
                while pre.right and pre.right != cur:
                    pre = pre.right
                # 跳出循环两种情况
                # 情况一:到达最右边
                # 建立线索
                if pre.right is None:
                    pre.right = cur
                    print(f"设置线索:{pre}->{cur}")
                    # 继续遍历左边
                    # 中序是遍历完左子树再遍历根
                    cur = cur.left
                # 情况二:遍历完左子树,进行回溯
                # 如果没有建立线索的二叉树是不会出现pre.right == cur的
                # 说明此处已经建立了线索,已经遍历过了
                # 线索二叉树的回溯是通过线索回溯的
                else:
                    pre.right = None    # 删掉线索,还原二叉树
                    print(f"删掉线索:{pre}->{cur}")
                    # 左边已经遍历完了,遍历右边
                    cur = cur.right

下面对我当时看到代码时产生的疑问进行解答:

问:为什么会有回溯过程?

答:它是一步一步进入左子树进行遍历的。如先进入root的左节点找前驱,再去root.left的左节点找前驱,那么叶子节点已经被建立联系了。当到达叶子节点时,无左节点,在进入右节点时会通过之间建立好的线索进行回溯到上一个节点,再重复建立过程,相当又要经历建立好的线索进行回溯。进而回溯到根节点(每个节点)再进入右子树进行遍历。

另外,删掉线索的那一行代码是可以注释掉的,这样就可以得到遍历后的树,而不是只是经历过程。

下面结合图片对过程进行理解,主要是理解过程,不必死磕过程。在博主的眼中,树是抽象且局部重复的,我们只需要关注局部,理解对局部的操作即可。

e5860b833f6e4873ac944bfef9166b4e.jpeg

2.对代码进行测试

写完一个代码还是需要对代码进行测试。作为一个初学者,我觉得记录下测试的方法还是很有必要的。 

(1)首先要初始化树

学习链接:http://t.csdnimg.cn/P1wB7

具体初始化代码就不写了,对学习链接代码进行修改即可。(ps:需要对树类名,和左右指针名进行修改哦)

另外,其中的运行结果在哪里查看呢?博主搜索后发现在Debug处查看。需要在操作后断点,断点如下:

482301620eb94e1c95d576066ce685dd.png

(2)对初始化后的树使用函数即可,再断点查看就行了(如上图第二处断点,记得注释掉删除线索的那一行代码)。

三、使用Morris中序遍历

练习题目:501. 二叉搜索树中的众数

博主是在遇到这道题时才来学习的这个方法,可以通过这道题来练习一下。

四、学习和参考视频

【【算法奇淫技】第1期  Morris遍历(二叉树的特殊遍历法)】 https://www.bilibili.com/video/BV13J411z7Z5/?share_source=copy_web&vd_source=dc0e55cfae3b304619670a78444fd795

 

感谢你看到这里!一起加油吧!

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1583806.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue的监视属性

目录 1. 场景引入2. watch3. 深度监视4. 监视属性简写5. 小结 1. 场景引入 在实际开发中,有时开发者需要根据某个属性的变化,做出相应的决策,因此Vue为开发者提供了watch.这一监视属性,用于实现此类需求。比如下面这个场景&…

【muzzik 分享】原生预览调试!我给Cocos加了个新功能,原生开发者福音

前言 一年一度的征稿到了,倒腾点存货,在之前阅读云风大佬文章的时候,发现他的引擎调试机制是在 手机上实时刷新预览,而不是在PC上调试,作为一个 Cocos 原生开发者,我深有体会,主要有以下原因 C…

一、Spring基础 --- 基础内容(二) (咕P4)

一、IOC容器 1.1 基础 1.1.1 容器 1、Spring框架的主要功能是通过其核心容器来实现的。2、Spring容器是生成Bean的工厂,它负责创建Bean的实例,并管理其生命周期。所有的组件都被当成Bean处理,例如数据源、Hibernate的SessionFactory、事务管…

【Keil5-报错】

Keil5-报错 ■ 调试烧录出现问题■ 烧录程序失败■ 编译报错 .\Objects\stm32h7_tms.axf: Error: L6218E: Undefined symbol __heap_base (referred from alloc.o).■ Keil5 load 出错■ No Space in execution regions with .ANY selector matching startup ...■ Execution r…

寄快递的省钱小妙招,看看你能知道多少

首先就是从包裹的重量上和体积上,我们都知道快递员上门取件都是需要称重的,我们能做的就是尽量压缩包裹的体积来减少快递的运费价格。然后是使用自己的包装袋来打包行李,快递员的袋子也是需要另外花费的。对于一些不容易损坏的货物来说&#…

基于SVM的时间序列预测模型matlab代码

整理了基于SVM的时间序列预测模型matlab代码, 包含数据集。采用了四个评价指标R2、MAE、MBE、MAPE对模型的进行评价。SVM模型在数据集上表现非常好。 Mean squared error 0.000180613 (regression) Squared correlation coefficient 0.995639 (regression) Mea…

了解单链表

27. 移除元素 - 力扣(LeetCode) 思路一: 创建新的数组,遍历原数组,将不为val的值放到新数组当中。空间复杂度不为O(1) 思路二:双指针法 我们设置两个指针src(源数据)和dst&#xf…

MOS管的判别符号记忆与导通条件

参考链接 MOS管的判别与导通条件 (qq.com)https://mp.weixin.qq.com/s?__bizMzU3MDU1Mzg2OQ&mid2247520228&idx1&sn5996780179fbf01f66b5db0c71622ac3&chksmfcef6c86cb98e590e3d3734ee27797bdded17b6b648b3b0d3b1599e8a4496a1fa4e457be6516&mpshare1&…

[CUDA 学习笔记] 矩阵转置算子优化

矩阵转置算子优化 矩阵转置是一种基础的矩阵操作, 即将二维矩阵的行列进行反转. 本文主要围绕行主序的二维单精度矩阵的转置考虑相关的优化. 以下 kernel 笔者均是在 NVIDIA V100 (7.0 算力) 上进行测试的, 且选择矩阵的行列维度大小为 M2300 N1500. Version 0. 朴素实现 _…

流量分组新增两大新规则;Network SDK更新618大促版本;综合报表支持实时新用户指标 | TopOn产品更新

「TopPro 每月产品速递」是由TopOn最新推出的产品专栏,将会以月为周期梳理TopOn最新产品动态,致力于为互联网从业者提供优质服务,引领行业产品发展。 TopPro | 四月产品速递 2023.04.01-04.27 01 流量分组新增两大新规则 // 功能描述 *…

面向AI编程,AI可以为我们做哪些事情

本来这篇文章是2023-10月发出的,放在草稿箱比较久了。今天重新捡起来发下。内容很长,很干。希望对大家有启发,编程路上提升效率。 背景 基本上以前我们出了bug都是百度,但随着AI的出现,对标百度给出的答案。发现AI实在…

python爬虫-------JsonPath(第十九天)

🎈🎈作者主页: 喔的嘛呀🎈🎈 🎈🎈所属专栏:python爬虫学习🎈🎈 ✨✨谢谢大家捧场,祝屏幕前的小伙伴们每天都有好运相伴左右,一定要天天…

Pytorch中nn.Linear使用方法

nn.Linear定义一个神经网络的线性层: torch.nn.Linear(in_features, # 输入的神经元个数out_features, # 输出神经元个数biasTrue # 是否包含偏置)nn.Linear其实就是对输入(n表示样本数量,i表示样本特…

国产低代码工具,轻松搞定数据迁移

在日常的业务系统升级或者数据维护过程中,数据迁移是各个企业用户不得不面临的问题,尤其是数据迁移过程中要保障数据完整性、统一性和及时性,同时也需要注意源数据中的数据质量问题,比如缺失、无效、错误等问题,需要在…

Kubernetes中安装部署Nacos集群

目录 1、Nacos安装包的准备 1.1 下载安装包 1.2 解压安装包 1.3 修改配置文件 application.properties 1.4 bin目录下创建 docker-startup.sh 1.5 将nacos-server-1.2.1目录打包成nacos-server-1.2.1.tar.gz 2、 nacos镜像制作 2.1 Dockerfile文件编写 2.2 制作镜像…

单片机入门还能从51开始吗?

选择从51单片机开始入门还是直接学习基于ARM核或RISC核的单片机,取决于学习目标、项目需求以及个人兴趣。每种单片机都有其特定的优势和应用场景,了解它们的特点可以帮助你做出更合适的选择。 首先,我们说一下51单片机的优势: 成熟…

外包干了17天,技术倒退明显

先说情况,大专毕业,18年通过校招进入湖南某软件公司,干了接近6年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能…

【石上星光】context,go的上下文存储并发控制之道

目录 1 引言2 What?3 How? 3.1 用法一、上下文数据存储3.2 用法二、并发控制 3.2.1 场景1 主动取消3.2.2 场景2 超时取消 3.3 用法三、创建一个空Context(emptyCtx) 4 Why? 4.1 go中的上下文思想 4.1.1 上下文是什么…

技术小课堂:100%CC防护是怎么实现的?

大家好,今天我们深入探讨的是如何有效地实现CC攻击的100%防护,以及传统防护手段存在的局限性和我们的定制化解决方案的优势。 传统的CC防护措施通常依赖于全局性的访问频率控制或在防火墙级别设置固定的访问次数限制。这种方式看似简单直接,…

安全大脑与盲人摸象

21世纪是数字科技和数字经济爆发的时代,互联网正从网状结构向类脑模型进行进化,出现了结构和覆盖范围庞大,能够适应不同技术环境、经济场景,跨地域、跨行业的类脑复杂巨型系统。如腾讯、Facebook等社交网络具备的神经网络特征&…