今天在切leetcode的时候看到一个Morris算法,用来中序遍历二叉树,非递归,O(1)空间。觉得很强大。记录一下。

基本思想是利用了Threaded Binary Tree

步骤如下:

  1. current节点设置为root。如果current不为空,到2,否则返回;
  2. 如果current没有左子树,输出current的值,current等于current.right;
  3. 如果current有左子树,首先找到current节点的precedent,也就是该节点左子树中最最右边那个节点。然后把最最右边这个节点的右link指向当前节点。如下图。

    e.g. 当current是7的时候,我们找到4,并人为地添加一个link到current(绿色的link)。

    current等于current.left;回到2.

有同学说,如果遍历到结点4,按照算法(4没有左子树),不是就又回到了7么,然后循环怎么结束呢?假设如果通过4回到了7,再找寻找7的precendent的过程中,我们会发现环,7->3->4->7(7的左子树中最最右边的节点是自己),那么我们知道7的左子树已经遍历完成,输出7,然后继续遍历7的右子树。

我们的代码如下:

首先假设有一个TreeNode数据结构是这样的。

 public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}

然后是遍历:

public ArrayList<Integer> inorderMorrisTraversal(TreeNode root){
sequence = new ArrayList<Integer>();
TreeNode current = root;
TreeNode pre = null;
while(current != null){
if(current.left == null){
sequence.add(current.val);
current = current.right;
}else {
pre = current.left;
//找到当前节点的前任,也就是它左子树的最右节点
while(pre.right != null && pre.right != current){
pre = pre.right;
}
if(pre.right == null){//我们遇到的左子树
pre.right = current;
current = current.left;
}else {//说明pre.right == current,构成了一个环,说明之前已经遍历过了current的左子树,可以输出current了。
pre.right = null;
sequence.add(current.val);
current = current.right;
}
}
}
return sequence;

我们以上面的例子track一下这个过程,首先current指向root节点7. root节点左子树非空,通过一路向右,找到7的前任4,建立绿色的link。

然后继续到3,在左子树中一路向右,找到2.

继续current = current.left,发现2没有左子树了,输出2.

然后current = current.right,current指向3. 注意到这是第二次指向3. 然后按照算法去寻找3的前任,当然这一回就不是2了,而是3本身。那么,我们需要删除掉这个环,也就2->3的link。并且输出current 的值3.

然后继续current到3的左子树。剩下的过程如下图。

      

总结下:

首先发明这个算法的人肯定是对那个什么Threaded Binary Tree烂熟于心啊;其次,对inorder遍历也是理解透彻啊。。。

再次,这人思维肯定特清晰。

Reference: http://www.geeksforgeeks.org/inorder-tree-traversal-without-recursion-and-without-stack/

Morris InOrder Traverse Binary Tree 无需使用递归和栈的更多相关文章

  1. CSharp Algorithm - How to traverse binary tree by breadth (Part II)

    /* Author: Jiangong SUN */ Here I will introduce the breadth first traversal of binary tree. The pri ...

  2. Post Order traverse binary tree using non-recursive way

    Process analysis Stack = 5,  Push 3, Stack = 5, 3.    Pre = 5 Current = 3, Pre = 5, Push 2 to the st ...

  3. [LeetCode] Binary Tree Preorder Traversal 二叉树的先序遍历

    Given a binary tree, return the preorder traversal of its nodes' values. For example:Given binary tr ...

  4. [LeetCode] Binary Tree Postorder Traversal 二叉树的后序遍历

    Given a binary tree, return the postorder traversal of its nodes' values. For example: Given binary ...

  5. [Algorithm] Construct a Binary Tree and Binary Search

    function createNode(value) { return { value, left: null, right: null }; } function BinaryTree(val) { ...

  6. [LeetCode] 145. Binary Tree Postorder Traversal 二叉树的后序遍历

    Given a binary tree, return the postorder traversal of its nodes' values. For example: Given binary ...

  7. [Leetcode][JAVA] Recover Binary Search Tree (Morris Inorder Traversal)

    Two elements of a binary search tree (BST) are swapped by mistake. Recover the tree without changing ...

  8. (二叉树 递归) leetcode94. Binary Tree Inorder Traversal

    Given a binary tree, return the inorder traversal of its nodes' values. Example: Input: [1,null,2,3] ...

  9. (二叉树 递归) leetcode 105. Construct Binary Tree from Preorder and Inorder Traversal

    Given preorder and inorder traversal of a tree, construct the binary tree. Note:You may assume that ...

随机推荐

  1. C++隐式转换与显式转换

    普通类型的转换顺序:隐式把char——>int和从short——>double.转换可能会导致数据的丢失. 自定义类型:有两种函数可以进行隐式转换,单参数构造函数 和 隐式类型转换符.   ...

  2. 关于Struts2的jsp页面的注释

    语句就算用<!-- -->注释后,还是会在编译的时候显示在网页上,而且网页还会报错,因为注释的那些语句也会去编译,也会去检查有没有错误,所以一些注释掉的过时的变量和方法也会导致报错.500

  3. HttpClient学习之 客户端HTTP编程入门

    说明 本文存在的原因,是想深入的学习下HttpClient.对应的网址是: http://hc.apache.org/httpcomponents-client-4.5.x/primer.html h ...

  4. ti8127下godb 开发

    http://download.cnet.com/GoDB/3000-2212_4-10306159.html源码rdk https://github.com/vasa-c/go-db github ...

  5. Python的可变对象与不可变对象。

    参考:http://thomaschen2011.iteye.com/blog/1441254          Python基础:Python可变对象和不可变对象 http://blog.jobbo ...

  6. Z字形扫描矩阵

    问题描述 在图像编码的算法中,需要将一个给定的方形矩阵进行Z字形扫描(Zigzag Scan).给定一个n×n的矩阵,Z字形扫描的过程如下图所示: 对于下面的4×4的矩阵, 1 5 3 9 3 7 5 ...

  7. 【Java面试题】3 Java的"=="和equals方法究竟有什么区别?简单解释,很清楚

    ==操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用==操作符. 如果一个变量指向的数据是对象类型的 ...

  8. Java 基本概念:jvm、jdk、jre、jse

    jvm 是java虚拟机,将java的class字节码文件翻译成二进制可执行程序.jdk 是java的开发包 Javasdk, java的开发工具,包含SUN公司提供的javaAPI,将java源码编 ...

  9. C语言中文件目录(一正二反)斜杠

    正斜杠unix“/” linux,安卓,苹果都是 windows是两个反斜杠“\\”,但现在也兼容了可以使用正斜杠“/”

  10. LLE局部线性嵌入算法

    非线性降维 流形学习 算法思想有些类似于NLM,但是是进行的降维操作. [转载自] 局部线性嵌入(LLE)原理总结 - yukgwy60648的博客 - CSDN博客 https://blog.csd ...