图解二叉树的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和prevTreeNode 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和prevTreeNode 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和prevTreeNode 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和prevTreeNode 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.hqwc.cn/news/297959.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go语言中的`sync`包同步原语

通过sync包掌握Go语言的并发 并发是现代软件开发的基本方面&#xff0c;而Go&#xff08;也称为Golang&#xff09;为并发编程提供了一套强大的工具。在Go中用于管理并发的基本包之一是sync包。在本文中&#xff0c;我们将概述sync包&#xff0c;并深入探讨其最关键的同步原语…

【重点!!!】【单调栈】84.柱状图中最大矩形

题目 法1&#xff1a;单调栈[原版] O(N)O(N) 必须掌握算法&#xff01;&#xff01;&#xff01; class Solution {public int largestRectangleArea(int[] heights) {int n heights.length, res 0;int[] leftMin new int[n], rightMin new int[n];Stack<Integer>…

ros2中gazebo安装的注意事项

Install From source&#xff08;推荐安装Fortress版本&#xff0c;好像很方便&#xff09; ROS Be sure youve installed ROS Humble (at least ROS-Base). More ROS dependencies will be installed below. Gazebo Install either Edifice, Fortress, or Garden.(没有har…

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

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

快速入门学习定时任务框架-xxljob

定时任务框架-xxljob 简介 主要用于分布式任务调度&#xff0c;可以将任务调度和执行分布在多个节点上。它提供了一个集中式的管理平台&#xff0c;支持动态添加、修改、删除任务&#xff0c;以及任务的分片执行&#xff0c;确保任务在分布式环境中的高可用性的一个框架 spr…

java数据结构与算法刷题-----LeetCode167:两数之和 II - 输入有序数组

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 思路 题目要求我们找到两个数相加的和&#xff0c;等于target指定的值。而…

reactor的原理与实现

网络模型 前情回顾服务器模型 Reactor和 ProactorReactor模型Proactor模型同步I/O模拟Poractor模型Libevent&#xff0c;libev&#xff0c;libuv优先级事件循环线程安全 前情回顾 网络IO&#xff0c;会涉及到两个系统对象&#xff1a;   一个是用户空间调用的进程或线程   …

机器学习或深度学习的数据读取工作(大数据处理)

机器学习或深度学习的数据读取工作&#xff08;大数据处理&#xff09;主要是.split和re.findall和glob.glob运用。 读取文件的路径&#xff08;为了获得文件内容&#xff09;和提取文件路径中感兴趣的东西(标签) 1&#xff0c;“glob.glob”用于读取文件路径 2&#xff0c;“.…

MQ(消息队列)相关知识

1. 什么是mq 消息队列是一种“先进先出”的数据结构 2. 应用场景 其应用场景主要包含以下3个方面 应用解耦 系统的耦合性越高&#xff0c;容错性就越低。以电商应用为例&#xff0c;用户创建订单后&#xff0c;如果耦合调用库存系统、物流系统、支付系统&#xff0c;任何…

选择排序(java)

选择排序 选择排序是默认前面都是已经排序好的&#xff0c;然后从后面 选择最小的放在前面排序好的的后面&#xff0c;首先第一轮循环的时候默认的排序好的为空&#xff0c;然后从后面选择最小的放到数组的第一个位置&#xff0c;第二轮循环的时候默认第个元素是已经 排序好的…

linux异步IO的几种方法及重点案例

异步IO的方法 在Linux下&#xff0c;有几种常见的异步I/O&#xff08;Asynchronous I/O&#xff09;机制可供选择。以下是其中一些主要的异步I/O机制&#xff1a; POSIX AIO&#xff08;Asynchronous I/O&#xff09;&#xff1a;POSIX AIO是一种标准的异步I/O机制&#xff0c…

裸机开发(1)-汇编基础

文章目录 GNU汇编语法常用汇编指令处理器内部数据传输指令存储器访问指令压栈和出栈指令跳转指令算术指令逻辑运算指令实战 函数发生调用时&#xff0c;需要进行线程保护&#xff0c;简单来说&#xff0c;就是先进行压栈操作&#xff0c;将调用函数参数、返回值等存到R0-15寄存…