程序员代码面试指南(第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次,每次都需要重新查找右边界。

  1. 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;
    }
    }
  2. 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();
    }
  3. 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();
    }
  4. 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莫里斯遍历的更多相关文章

  1. 数据结构《13》----二叉树 Morris 前序遍历

    三种二叉树的后序遍历的方法: 1. 递归                      O(n) 时间复杂度, O(n) 空间复杂度 2. 迭代(用栈)       O(n) 时间复杂度, O(n) 空间 ...

  2. 二叉树遍历,递归,栈,Morris

    一篇质量非常高的关于二叉树遍历的帖子,转帖自http://noalgo.info/832.html 二叉树遍历(递归.非递归.Morris遍历) 2015年01月06日 |  分类:数据结构 |  标 ...

  3. 《程序员代码面试指南》第三章 二叉树问题 遍历二叉树的神级方法 morris

    题目 遍历二叉树的神级方法 morris java代码 package com.lizhouwei.chapter3; /** * @Description:遍历二叉树的神级方法 morris * @ ...

  4. Morris 遍历实现二叉树的遍历

    Morris 遍历实现二叉树的遍历 作者:Grey 原文地址: 博客园:Morris 遍历实现二叉树的遍历 CSDN:Morris 遍历实现二叉树的遍历 说明 Morris 遍历可以实现二叉树的先,中 ...

  5. [Alg] 二叉树的非递归遍历

    1. 非递归遍历二叉树算法 (使用stack) 以非递归方式对二叉树进行遍历的算法需要借助一个栈来存放访问过得节点. (1) 前序遍历 从整棵树的根节点开始,对于任意节点V,访问节点V并将节点V入栈, ...

  6. 二叉树的N中遍历方式和拓展应用

    (一)创建二叉树,如下图所示,一个标准的二叉树是所有位于根节点的左侧的子节点都是比根节点小的,右侧则都是大于根节点的. public class BinaryNode { public int val ...

  7. Leetcode 笔记 99 - Recover Binary Search Tree

    题目链接:Recover Binary Search Tree | LeetCode OJ Two elements of a binary search tree (BST) are swapped ...

  8. [LeetCode] Binary Tree Preorder/Inorder/Postorder Traversal

    前中后遍历 递归版 /* Recursive solution */ class Solution { public: vector<int> preorderTraversal(Tree ...

  9. 树及其衍生算法(Trees and tree algorithms)

    1,二叉树(Binary tree) 二叉树:每一个节点最多两个子节点,如下图所示: 相关概念:节点Node,路径path,根节点root,边edge,子节点 children,父节点parent,兄 ...

随机推荐

  1. ZeptoLab Code Rush 2015 B. Om Nom and Dark Park

    Om Nom is the main character of a game "Cut the Rope". He is a bright little monster who l ...

  2. 使用eclipse搭建第一个java web应用

    一. 首先是eclipse得下载,你要下载Eclipse IDE for Java EE这种类型的,我之前下载的Eclipse IDE for Enterprise Java Developers是官 ...

  3. 最新版gradle安装使用简介

    目录 简介 安装gradle和解决gradle安装的问题 Gradle特性 标准task Build phases Gradle Wrapper wrapper的使用 wrapper的升级 一个简单的 ...

  4. EFCore学习记录--数据访问技术人门2

    1 code fist 1.创建实体类: 2.创建DbContext类: mysql连接字符串是:Server=127.0.0.1;Port=3306;Database=BlogDb; User=ro ...

  5. 动态链接库(DLL)的创建和使用

    最近想做个记录日志的C++库,方便后续使用.想着使用动态库,正好没用过,学习下.概念这里不赘述.学习过程中碰到的几点,记录下来.学习是个渐进的过程,本文也是一个逐渐完善的过程. 一.Static Li ...

  6. XV6学习(16)Lab net: Network stack

    最后一个实验了,代码在Github上. 这一个实验其实挺简单的,就是要实现网卡的e1000_transmit和e1000_recv函数.不过看以前的实验好像还要实现上层socket相关的代码,今年就只 ...

  7. linux运维面试精华题

    Linux运维跳槽面试精华题|第一集 1.什么是运维?什么是游戏运维? 1)运维是指大型组织已经建立好的网络软硬件的维护,就是要保证业务的上线与运作的正常,在他运转的过程中,对他进行维护,他集合了网络 ...

  8. Leetcode(198)-打家劫舍

    你是一个专业的小偷,计划偷窃沿街的房屋.每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警. 给定一个代表每 ...

  9. CNN可视化技术总结(三)--类可视化

    CNN可视化技术总结(一)-特征图可视化 CNN可视化技术总结(二)--卷积核可视化 导言: 前面我们介绍了两种可视化方法,特征图可视化和卷积核可视化,这两种方法在论文中都比较常见,这两种更多的是用于 ...

  10. Chrome new features preview

    Chrome new features preview CSS Overview https://css-tricks.com/new-in-chrome-css-overview/ capture ...