Morris 遍历实现二叉树的遍历作者:Grey
原文地址:
博客园:Morris 遍历实现二叉树的遍历
CSDN:Morris 遍历实现二叉树的遍历
说明Morris 遍历可以实现二叉树的先,中 , 后序遍历,且时间复杂度O(N)
, 空间复杂度可以做到O(1)
。
Morris 遍历流程假设有一棵如下的二叉树
文章插图
Morris遍历的流程主要分如下几个步骤:
第一步,从头节点开始遍历 。
第二步,假设当前遍历的节点是
cur
。第三步,如果
cur
无左树, cur
来到其右树上,即:cur = cur.right
第四步,如果
cur
有左树,找到cur
左树最右节点,假设叫mostRight
,则有如下两种小情况:情况1,如果
mostRight
的右指针指向空, 则将mostRight
的右指针指向cur
,即:mostRight.right = cur
, 然后将cur
向左移动,即:cur = cur.left
,情况2,如果
mostRight
的右指针指向当前节点cur
, 则将mostRight
的右指针指向空 , 即:mostRight.right = null
, 然后将cur
向右移动,即:cur = cur.right
。第五步:当
cur = null
,遍历结束 。根据如上流程,示例二叉树的Morris遍历序列为:
【Morris 遍历实现二叉树的遍历】
1-->2-->4-->7-->11-->7-->4-->8-->12-->8-->1-->3-->5-->3-->6-->9-->13-->6-->10
Morris遍历可以实现在O(N)
时间复杂度内 , 用O(1)
的空间复杂度实现对树的遍历,而且,只要某个节点有右树 , 则这个节点一定会被遍历两次,我们可以通过Morris遍历来实现二叉树的先,中,后序遍历 , 做到时间复杂度O(N)
,空间复杂度O(1)
。代码实现如下:
public class Code_Morris {//当前是cur//1. cur无左树,cur = cur.right//2. cur有左树,找到左树最右节点mostRight// a. mostRight的右指针指向null, mostRight.right = cur, cur = cur.right// b. mostRight的右指针指向当前节点cur , mostRight.right = null, cur = cur.right//3. cur = null 停public static void morrisPrint(TreeNode head) {if (head == null) {return;}System.out.println("....morris order....");TreeNode cur = head;System.out.print(cur.val + "-->");TreeNode mostRight;while (cur != null) {mostRight = cur.left;if (mostRight != null) {while (mostRight.right != null && mostRight.right != cur) {mostRight = mostRight.right;}if (mostRight.right == null) {mostRight.right = cur;cur = cur.left;System.out.print(cur.val + "-->");continue;} else {mostRight.right = null;}}cur = cur.right;if (cur != null) {System.out.print(cur.val + "-->");}}}}
Morris遍历实现先序遍历根据Morris的遍历结果 , 没有右树的点只会遍历一次,有右树的点会遍历两次,针对遍历一次的点,遍历到就收集 , 针对遍历两次的点,第一次遍历到就收集,第二次遍历到不收集 , 整个流程跑完,则得到了先序遍历的结果 。代码如下:
public static List<Integer> preorderTraversal(TreeNode root) {if (null == root) {return new ArrayList<>();}List<Integer> ans = new ArrayList<>();TreeNode mostRight;TreeNode cur = root;while (cur != null) {mostRight = cur.left;if (mostRight != null) {while (mostRight.right != null && mostRight.right != cur) {mostRight = mostRight.right;}if (mostRight.right == null) {// 有右树,第一次来到自己就收集ans.add(cur.val);mostRight.right = cur;cur = cur.left;continue;} else {// mostRight.right = cur;mostRight.right = null;}} else {// 没有右树的,来到就收集ans.add(cur.val);}cur = cur.right;}return ans;}
测评链接:LeetCode 144. Binary Tree Preorder TraversalMorris遍历实现中序遍历针对遍历一次的点,遍历到就收集,针对遍历两次的点 , 第一次遍历到不收集,第二次遍历才收集,整个流程跑完 , 则得到了中序遍历的结果 。
代码如下:
class Solution {public List<Integer> inorderTraversal(TreeNode root) {if (root == null) {return new ArrayList<>();}List<Integer> ans = new ArrayList<>();TreeNode mostRight;TreeNode cur = root;while (cur != null) {mostRight = cur.left;if (mostRight != null) {while (mostRight.right != null && mostRight.right != cur) {mostRight = mostRight.right;}if (mostRight.right == null) {mostRight.right = cur;cur = cur.left;continue;} else {// 来到自己两次的点,第二次来到才收集ans.add(cur.val);mostRight.right = null;}} else {// 只来到自己一次的点,来到就收集ans.add(cur.val);}cur = cur.right;}return ans;}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- vue实现功能 单选 取消单选 全选 取消全选
- VLQ & Base64 VLQ 编码方式的原理及代码实现
- Object Detection 【YOLOv5】LabVIEW+YOLOv5快速实现实时物体识别含源码
- 驱动开发:内核遍历进程VAD结构体
- Springboot 之 Filter 实现超大响应 JSON 数据压缩
- SpringBoot 自定义注解 实现多数据源
- .NET 采用 SkiaSharp 生成二维码和图形验证码及图片进行指定区域截取方法实现
- 驱动开发:内核中实现Dump进程转储
- OnionArch - 如何实现更新指定字段的通用Handler
- 如何用AR Engine环境Mesh能力实现虚实遮挡