zoukankan      html  css  js  c++  java
  • Morris InOrder Traverse Binary Tree 无需使用递归和栈

    今天在切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数据结构是这样的。

    1 public class TreeNode {
    2      int val;
    3      TreeNode left;
    4      TreeNode right;
    5      TreeNode(int x) { val = x; }
    6 }

    然后是遍历:

    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;
    View Code

    我们以上面的例子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/

  • 相关阅读:
    ajax 拼接html标签 thinkphp
    使用Log4J进行日志操作
    学习Spark2.0中的Structured Streaming(一)
    互联网日志实时收集和实时计算的简单方案
    Integer.valueOf方法的源码解读
    spark的ML和MLLib两个包区别和联系?
    数组和集合区别
    Java中的集合类
    Spark会把数据都载入到内存么?
    可变参数
  • 原文地址:https://www.cnblogs.com/lichen782/p/Morris_InOrder_Traverse_Binary_Tree.html
Copyright © 2011-2022 走看看