Morris莫里斯遍历
程序员代码面试指南(第2版)第3章 二叉树问题:遍历二叉树的神级方法
https://leetcode.com/articles/binary-tree-inorder-traversal/
Step 1: Initialize current as root
Step 2: While current is not NULL,
If current does not have left child
a. Add current’s value b. Go to the right, i.e., current = current.right
Else
If rightmost node of current's left subtree has no right child
a. In current's left subtree, make current the right child of the rightmost node b. Go to this left child, i.e., current = current.left
Else
a. Restore the origianl state, assign null value to the right child of the rightmost node
在了解Morris序后,通过对能到达2次的节点选择性的打印,可以很直观的得到前序遍历和中序遍历。
对于Morris序,先把左子树的右边界节点和cur连上,再处理左子树。(这个查找左子树右边界节点的过程不属于Morris遍历过程。)
cur被指针保存后,就可以放心的移动了。
有左子树的节点都会到达2次,每次都需要重新查找右边界。
Morris遍历
public static void morris(Node head) {
if (head == null) {
return;
}
Node cur = head;
//这个mostRight指的是左子树的mostRight,而不是当前节点的mostRight
Node mostRight = null;
while (cur != null) {
mostRight = cur.left;
if (mostRight != null) { // 如果当前cur有左子树
// 找到cur左子树上最右的节点
while (mostRight.right != null && mostRight.right != cur) {
mostRight = mostRight.right;
}
// 从上面的while里出来后,mostRight就是cur左子树上最右的节点
if (mostRight.right == null) { // 如果mostRight.right是指向null的
mostRight.right = cur; // 让其指向cur
cur = cur.left; // cur向左移动
continue; // 回到最外层的while,继续判断cur的情况
} else { // 如果mostRight.right是指向cur的
mostRight.right = null; // 让其指向null
}
}
// cur如果没有左子树,cur向右移动
// 或者cur左子树上最右节点的右指针是指向cur的,cur向右移动
cur = cur.right;
}
}
Morris前序遍历
对于只到达1次的节点,马上打印。
对于到达2次的节点,只打印第1次。
public static void morrisPre(Node head) {
if (head == null) {
return;
}
Node cur = head;
Node mostRight = null;
while (cur != null) {
mostRight = cur.left;
if (mostRight != null) {
//到达2次的节点
while (mostRight.right != null && mostRight.right != cur) {
mostRight = mostRight.right;
}
if (mostRight.right == null) {
//2次中的第1次
mostRight.right = cur;
System.out.print(cur.value + " ");
cur = cur.left;
continue;
} else {
//2次中的第2次
mostRight.right = null;
}
} else {
//只能到达1次的节点
System.out.print(cur.value + " ");
}
cur = cur.right;
}
System.out.println();
}
Morris中序遍历
对于只到达1次的节点,马上打印。
对于到达2次的节点,只打印第2次。
public static void morrisIn(Node head) {
if (head == null) {
return;
}
Node cur = head;
Node mostRight = null;
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 {
mostRight.right = null;
}
}
//只能到达1次的节点和能到达2次中的节点的第2次,会经过这里
System.out.print(cur.value + " ");
cur = cur.right;
}
System.out.println();
}
Morris后序遍历
对于第二次遇到的节点,打印其左子树的右边界。
最后打印整棵树的右边界。
public static void morrisPos(Node head) {
Node cur = head;
Node mostRight = null;
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 {
mostRight.right = null;
traverseRightEdge(head);
}
}
cur = cur.right;
}
traverseRightEdge(head);
} private static void traverseRightEdge(Node head) {
Node tail = reverseRightEdge(head);
for (Node cur = tail; cur != null; cur = cur.right) {
doSomething(cur);
}
reverseRightEdge(tail);
} private static Node reverseRightEdge(Node head) {
Node newHead = null;
Node next = null;
while (head != null) {
next = head.right;
head.right = newHead;
newHead = head;
head = next;
}
return newHead;
} private static void doSomething() {}
Morris莫里斯遍历的更多相关文章
- 数据结构《13》----二叉树 Morris 前序遍历
三种二叉树的后序遍历的方法: 1. 递归 O(n) 时间复杂度, O(n) 空间复杂度 2. 迭代(用栈) O(n) 时间复杂度, O(n) 空间 ...
- 二叉树遍历,递归,栈,Morris
一篇质量非常高的关于二叉树遍历的帖子,转帖自http://noalgo.info/832.html 二叉树遍历(递归.非递归.Morris遍历) 2015年01月06日 | 分类:数据结构 | 标 ...
- 《程序员代码面试指南》第三章 二叉树问题 遍历二叉树的神级方法 morris
题目 遍历二叉树的神级方法 morris java代码 package com.lizhouwei.chapter3; /** * @Description:遍历二叉树的神级方法 morris * @ ...
- Morris 遍历实现二叉树的遍历
Morris 遍历实现二叉树的遍历 作者:Grey 原文地址: 博客园:Morris 遍历实现二叉树的遍历 CSDN:Morris 遍历实现二叉树的遍历 说明 Morris 遍历可以实现二叉树的先,中 ...
- [Alg] 二叉树的非递归遍历
1. 非递归遍历二叉树算法 (使用stack) 以非递归方式对二叉树进行遍历的算法需要借助一个栈来存放访问过得节点. (1) 前序遍历 从整棵树的根节点开始,对于任意节点V,访问节点V并将节点V入栈, ...
- 二叉树的N中遍历方式和拓展应用
(一)创建二叉树,如下图所示,一个标准的二叉树是所有位于根节点的左侧的子节点都是比根节点小的,右侧则都是大于根节点的. public class BinaryNode { public int val ...
- Leetcode 笔记 99 - Recover Binary Search Tree
题目链接:Recover Binary Search Tree | LeetCode OJ Two elements of a binary search tree (BST) are swapped ...
- [LeetCode] Binary Tree Preorder/Inorder/Postorder Traversal
前中后遍历 递归版 /* Recursive solution */ class Solution { public: vector<int> preorderTraversal(Tree ...
- 树及其衍生算法(Trees and tree algorithms)
1,二叉树(Binary tree) 二叉树:每一个节点最多两个子节点,如下图所示: 相关概念:节点Node,路径path,根节点root,边edge,子节点 children,父节点parent,兄 ...
随机推荐
- 2017-2018 ACM-ICPC, Asia Daejeon Regional Contest PART(10/12)
$$2017-2018\ ACM-ICPC,\ Asia\ Daejeon\ Regional\ Contest$$ \(A.Broadcast\ Stations\) \(B.Connect3\) ...
- P2062 分队问题(DP)
题目描述 给定n个选手,将他们分成若干只队伍.其中第i个选手要求自己所属的队伍的人数大等于a[i]人. 在满足所有选手的要求的前提下,最大化队伍的总数. 注:每个选手属于且仅属于一支队伍. 输入输出格 ...
- HihoCoder - 1110
题意: 您的任务是判断输入是否是合法的正则表达式.正则表达式定义如下: 1: 0和1都是正则表达式. 2:如果P和Q是正则表达式,那么PQ就是正则表达式. 3:如果P是正则表达式,(P)就是正则表达式 ...
- xml——dom&sax解析、DTD&schema约束
dom解析实例: 优点:增删改查一些元素等东西方便 缺点:内存消耗太大,如果文档太大,可能会导致内存溢出 sax解析: 优点:内存压力小 缺点:增删改比较复杂 当我们运行的java程序需要的内存比较大 ...
- Dubbo和SpringCloud的优劣势比较--总体架构
从整体架构上来看 二者模式接近,都需要服务提供方,注册中心,服务消费方.差异不大.详见下方: Dubbo Provider: 暴露服务的提供方,可以通过jar或者容器的方式启动服务 Consumer: ...
- Python_变量作用域与修改
引用全局变量,不需要golbal声明,修改全局变量,需要使用global声明,特别地,列表.字典等如果只是修改其中元素的值(而不是整体赋值的形式),可以直接使用全局变量,不需要global声明. 参考 ...
- 排序算法 以及HKU的一些数据结构 相关题目 以及 K叉树,二叉树 排列
冒泡排序.选择排序.快速排序.插入排序.希尔排序.归并排序.基数排序以及堆排序,桶排序 https://www.cnblogs.com/Glory-D/p/7884525.html https://b ...
- 7816协议时序和采用UART模拟7816时序与智能卡APDU指令协议
7816时序 7816时一个比较早的老通讯时序了,最近项目上需要用UART模拟所以,简单学习时序. 时序比较简单,熟悉UART的一眼看着就像是串口的时序,只是他没有停止位,取而代之的就是保护时间gur ...
- hihoCoder Challenge 1
#1034 : 毁灭者问题 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在 Warcraft III 之冰封王座中,毁灭者是不死族打三本后期时的一个魔法飞行单位. 毁 ...
- CSS 弹性盒子模型
CSS 弹性盒子模型 https://www.w3.org/TR/2016/CR-css-flexbox-1-20160526/ CSS Flexible Box Layout Module Leve ...