图解二叉树的Morris(莫里斯)遍历

二叉树的Morris(莫里斯)遍历

本文参考链接:https://leetcode.cn/problems/binary-tree-preorder-traversal/submissions/490846864/

文章目录

    • 二叉树的Morris(莫里斯)遍历
      • 模板代码
      • 前序遍历
      • 中序遍历
      • 后序遍历

Morris 遍历使用二叉树节点中大量指向 null 的指针,时间复杂度:O(n),额外空间复杂度:O(1)。

Morris 的整体思路就是将 以某个根结点开始,找到它左子树的最右侧节点之后与这个根结点进行连接。

在这里插入图片描述

我们可以从图中看到,连接之后,指针是可以完整的从根节点顺着下一个节点遍历,将整棵树遍历完毕,直到 7 这个节点右侧没有指向。

模板代码

首先介绍morris的模板代码,带*的注释表示该行为指定遍历所要增加的内容,可以先不管。

模板代码的流程图如下所示:

在这里插入图片描述

在这里插入图片描述

public List<Integer> traversal(TreeNode root) {
    List<Integer> res = new ArrayList<>();
    if (root == null) {
        return res;
    }

    //1.定义cur和prev
    TreeNode cur = root;
    TreeNode prev = null;

    //2.当cur不为空时
    while (cur != null) {
        //2.1prev为cur左子树
        prev = cur.left;

        //2.2prev不为空时
        if (prev != null) {
            //2.2.1用prev找到左子树最右侧节点
            while (prev.right != null && prev.right != cur) {
                prev = prev.right;
            }

            //2.2.2prev右子树不为空时,连接
            if (prev.right == null) {
                prev.right = cur;
                //*前+res.add(cur.val);
                cur = cur.left;
            } else { //2.2.3prev右子树不为空时,断开连接
                prev.right = null;
                //*中+res.add(cur.val); *后+print(cur.left)
                cur = cur.right;
            }
        } else { //2.3prev为空时
            //*前中+res.add(cur.val);
            cur = cur.right;
        }
    }
    //*后+print(root)
    return res;
}

前序遍历

public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> res = new ArrayList<>();
    if (root == null) {
        return res;
    }

    //1.定义cur和prev
    TreeNode cur = root;
    TreeNode prev = null;

    //2.当cur不为空时
    while (cur != null) {
        //2.1prev为cur左子树
        prev = cur.left;

        //2.2prev不为空时
        if (prev != null) {
            //2.2.1用prev找到左子树最右侧节点
            while (prev.right != null && prev.right != cur) {
                prev = prev.right;
            }

            //2.2.2prev右子树不为空时,连接
            if (prev.right == null) {
                prev.right = cur;
                res.add(cur.val);
                cur = cur.left;
            } else { //2.2.3prev右子树不为空时,断开连接
                prev.right = null;
                cur = cur.right;
            }
        } else { //2.3prev为空时
            res.add(cur.val);
            cur = cur.right;
        }
    }
    return res;
}

中序遍历

public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> res = new ArrayList<>();
    if (root == null) {
        return res;
    }

    //1.定义cur和prev
    TreeNode cur = root;
    TreeNode prev = null;

    //2.当cur不为空时
    while (cur != null) {
        //2.1prev为cur左子树
        prev = cur.left;

        //2.2prev不为空时
        if (prev != null) {
            //2.2.1用prev找到左子树最右侧节点
            while (prev.right != null && prev.right != cur) {
                prev = prev.right;
            }

            //2.2.2prev右子树不为空时,连接
            if (prev.right == null) {
                prev.right = cur;
                cur = cur.left;
            } else { //2.2.3prev右子树不为空时,断开连接
                prev.right = null;
                res.add(cur.val);
                cur = cur.right;
            }
        } else { //2.3prev为空时
            res.add(cur.val);
            cur = cur.right;
        }
    }
    return res;
}

后序遍历

当连接已完成时,断开连接后,打印下层的单链表,比如返回到2时,打印4,返回到1时,打印5,2,涉及到了逆序打印单链表的内容。注意应该是打印下一层,而不是当前层。循环结束后打印根节点所在的一侧,即7,3,1。

在这里插入图片描述

List<Integer> res = new ArrayList<>();
public List<Integer> postorderTraversal(TreeNode root) {

    if (root == null) {
        return res;
    }

    //1.定义cur和prev
    TreeNode cur = root;
    TreeNode prev = null;

    //2.当cur不为空时
    while (cur != null) {
        //2.1prev为cur左子树
        prev = cur.left;

        //2.2prev不为空时
        if (prev != null) {
            //2.2.1用prev找到左子树最右侧节点
            while (prev.right != null && prev.right != cur) {
                prev = prev.right;
            }

            //2.2.2prev右子树不为空时,连接
            if (prev.right == null) {
                prev.right = cur;
                cur = cur.left;
            } else { //2.2.3prev右子树不为空时,断开连接
                prev.right = null;
                print(cur.left); //打印左子树
                cur = cur.right;
            }
        } else { //2.3prev为空时
            cur = cur.right;
        }
    }
    print(root); //打印根节点所在一侧
    return res;
}

//打印链表
public void print(TreeNode head) {
    TreeNode revList = reverseList(head);
    TreeNode cur = revList;
    while (cur != null) {
        res.add(cur.val);
        cur = cur.right;
    }
    reverseList(revList);
}

//翻转单链表
public TreeNode reverseList(TreeNode head) {
    TreeNode cur = head;
    TreeNode prev = null;

    while (cur != null) {
        TreeNode next = cur.right;
        cur.right = prev;
        prev = cur;
        cur = next;
    }
    return prev;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Apache Commons CLI:构建命令行应用的利器

引言 大家好&#xff01;我是小黑&#xff0c;本文聊聊如何用Apache Commons CLI构建命令行应用。咱们都知道&#xff0c;命令行界面&#xff08;CLI&#xff09;虽然看起来不如图形界面那么花哨&#xff0c;但在许多场景下&#xff0c;它的效率和便利性是无与伦比的。特别是对…

设计模式--命令模式

实验16&#xff1a;命令模式 本次实验属于模仿型实验&#xff0c;通过本次实验学生将掌握以下内容&#xff1a; 1、理解命令模式的动机&#xff0c;掌握该模式的结构&#xff1b; 2、能够利用命令模式解决实际问题。 [实验任务]&#xff1a;多次撤销和重复的命令模式 某系…

uni-app之HelloWorld实现

锋哥原创的uni-app视频教程&#xff1a; 2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中..._哔哩哔哩_bilibili2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中...共计23条视频&#xff0c;包括&#xff1a;第1讲 uni…

Codeforces Round 917 (Div. 2)(A~D)(又是数学题)

A - Least Product 题意&#xff1a; 思路&#xff1a;若有奇数个负数&#xff0c;则不需要任何操作。若存在0&#xff0c;也不需要任何操作。其余情况将任意一个数改为0即可。 #include <bits/stdc.h> using namespace std; void solve() {int n;cin >> n;int …

第十五节TypeScript 接口

1、简介 接口是一系列抽象方法的声明&#xff0c;是一些方法特征的集合&#xff0c;这些方法都应该是抽象的&#xff0c;需要有由具体的类去实现&#xff0c;然后第三方就可以通过这组抽象方法调用&#xff0c;让具体的类执行具体的方法。 2、接口的定义 interface interface_…

编程规范:长函数的思考

在工作&#xff0c;我们应该都不想看到非常的长函数。对于一个运行5年左右的项目&#xff0c;极有可能出现这种情况。由于长函数的长、if/else嵌套&#xff0c;导致代码的可读性非常差&#xff0c;这对于项目的维护和开发带来了极大的困难。所以我们应该避免写长函数&#xff0…

OpenAI科学家Hyung Won Chung演讲精华版

文章目录 第一个观点&#xff1a;涌现第二个观点&#xff1a;如何扩大规模1、标记化2、嵌入3、计算4、评估&#xff08;损失函数&#xff09;5、反向传播 最近从Google跳槽到OpenAI的AI科学家 Hyung Won Chung 比较拗口&#xff0c;我就简称尚哥了 他最近做了一个技术演讲 …

智能化中的控制与自动化中的控制不同

智能化中的控制相对于自动化中的控制更加灵活、智能、综合和学习能力强。智能化控制系统能够根据实际情况进行自主决策和优化&#xff0c;适用范围更广&#xff0c;效果更好。 首先&#xff0c;智能化控制系统能够根据外部环境的变化和实时数据的反馈来自主调整和优化控制策略&…

java实现深度优先搜索 (DFS) 算法

度优先搜索&#xff08;Depth First Search&#xff0c;DFS&#xff09;算法是一种用于遍历或搜索图或树的算法。这种算法从一个节点开始&#xff0c;沿着一条路径尽可能深地搜索&#xff0c;直到遇到不能继续前进的节点时返回上一个节点&#xff0c;然后继续搜索其他路径。具体…

Mac 右键拷贝文件失效

问题&#xff1a;Mac 右键拷贝文件失效&#xff0c;有时候拷贝可以成功&#xff0c;有时候拷贝不成功 发现问题所在&#xff1a;开了百度翻译的划词&#xff0c; 解决&#xff1a;把划词关掉就好了&#xff0c;或者设置划词快捷键翻译就好了&#xff0c;反正就不要一划就翻译那…

案例167:基于微信小程序的校园失物招领小程序

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

三道C语言中常见的笔试题及答案(一)

题目一&#xff1a; 问题&#xff1a; 解释以下代码中的#define预处理指令的作用&#xff0c;并说明其优点和缺点。 #include <stdio.h> #define PI 3.14159 #define CALCULATE_AREA(r) (PI * r * r) int main() { double radius 5.0; double area CALCULATE_AREA(r…

线程的同步与互斥

抢票的例子 竞争过程 进程A被切走 进程B被切走 结论&#xff1a; 互斥 int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); mutex: 指向要初始化的互斥锁的指针。attr: 用于设置互斥锁属性的指针&#xff0c;通常可以传入 NULL 以使用默认属性…

Node.js教程-express框架

概述 Express是基于Node.js平台(建立在Node.js内置的http模块上)&#xff0c;快速、开放、极简的Web开发框架。 中文官网 http://www.expressjs.com.cn/。 Github地址&#xff1a;https://github.com/orgs/expressjs。 Express核心特性&#xff1a; 可设置中间件来响应 HTTP…

智能优化算法应用:基于法医调查算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于法医调查算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于法医调查算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.法医调查算法4.实验参数设定5.算法结果6.…

基于阿里云服务网格流量泳道的全链路流量管理(二):宽松模式流量泳道

作者&#xff1a;尹航 在前文基于阿里云服务网格流量泳道的全链路流量管理&#xff08;一&#xff09;&#xff1a;严格模式流量泳道中&#xff0c;我们介绍了使用服务网格 ASM 的严格模式流量泳道进行全链路灰度管理的使用场景。该模式对于应用程序无任何要求&#xff0c;只需…

4. java——多态(java巅峰设计,超越了C++的理解,取其精华,去其糟粕)

多态指的是同—个行为具有多个不同表现形式 。是指—个类实例(对象&#xff09;的相同方法在不同情形下具有 不同表现形式。封装和继承是多态的基础&#xff0c;也就是说&#xff0c;多态只是—种表现形式而已。一个对象&#xff0c;同一个方法不同形态&#xff0c;方法必须重…

Redis源码精读:准备工作

文章目录 前言拉取源码项目结构源码阅读技巧最后 前言 我是醉墨居士&#xff0c;未来的一段时间里面我准备写一些关于Redis源码的文章&#xff0c;来帮助大家深入浅出Redis&#xff0c;希望大家多多支持&#x1fae0; 拉取源码 git clone https://github.com/redis/redis项目…

大数据----基于sogou.500w.utf8数据的MapReduce编程

目录 一、前言二、准备数据三、编程实现3.1、统计出搜索过包含有“仙剑奇侠传”内容的UID及搜索关键字记录3.2、统计rank<3并且order>2的所有UID及数量3.3、上午7-9点之间&#xff0c;搜索过“赶集网”的用户UID3.4、通过Rank&#xff1a;点击排名 对数据进行排序 四、参…

爬虫响应cookie阿里系案例:某财经

声明&#xff1a; 该文章为学习使用&#xff0c;严禁用于商业用途和非法用途&#xff0c;违者后果自负&#xff0c;由此产生的一切后果均与作者无关 一、响应cookie阿里系特点 cookie中一定有acw_sc__v2清除所有cookie刷新页面时&#xff0c;会自动debugger到设置cookie的文件…