Morris遍历遍历二叉树

Posted wangkaipeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Morris遍历遍历二叉树相关的知识,希望对你有一定的参考价值。

遍历二叉树的递归方法使用了函数栈,非递归方法使用了申请的栈,

两者的额外空间都与树的高度有关,所以空间复杂度为O(h),h为二叉树的高度。

 

可以使用二叉树叶子节点中大量指向null的指针实现空间复杂度O(1)的遍历。

Morris遍历的实质就是避免使用栈结构,让下层到上层有指针,

体是通过让底层节点指向null的空闲指针指回上层的某个节点,从而完成下层到上层的移动。

 

先序中序后序主要基于两个主要步骤,然后输出的位置有所不同,以中序遍历为例。

 

中序遍历:

1、假设当前子树的头节点为h,让h的左子树中最右节点的right指针指向h,

然后h的左子树继续步骤1的处理过程,直到遇到某一个节点没有左子树时记为node,进入步骤2。

 

2、从node开始通过每个节点的right指针进行移动并以此打印,假设移动到的节点为cur。

对每一个cur节点都判断cur节点的左子树中最右节点是否指向cur。

Ⅰ 如果是,令cur节点的左子树中最右节点的right指针指向null,即恢复树的本来面貌,

然后打印cur,继续通过cur的right指针移动到下一个节点。重复步骤2。

Ⅱ 如果不是,以cur为头的子树重回步骤1执行。

public void morrisIn(TreeNode root) {
        if (root == null)
            return;
        TreeNode cur1 = root;
        TreeNode cur2 = null;
        while (cur1 != null) {
            cur2 = cur1.left;
            if (cur2 != null) {
                // 找到cur1左子树的最右节点
                while (cur2.right != null && cur2.right != cur1)
                    cur2 = cur2.right;
                // cur2.right == null 则往上链接
                if (cur2.right == null) {
                    cur2.right = cur1;
                    cur1 = cur1.left;
                    continue;
                }
                // cur2.right == cur1 则取消链接
                else {
                    cur2.right = null;
                }
            }
            System.out.println(cur1.val);
            cur1 = cur1.right;
        }
    }

 

先序遍历:

和中序遍历相比差别不大,调整了打印顺序。

public void morrisPre(TreeNode root) {
        if (root == null)
            return;
        TreeNode cur1 = root;
        TreeNode cur2 = null;
        while (cur1 != null) {
            cur2 = cur1.left;
            if (cur2 != null) {
                while (cur2.right != null && cur2.right != cur1)
                    cur2 = cur2.right;
                if (cur2.right == null) {
                    cur2.right = cur1;
                    System.out.println(cur1.val);
                    cur1 = cur1.left;
                    continue;
                } else {
                    cur2.right = null;
                }
            } else {
                System.out.println(cur1.val);
            }
            cur1 = cur1.right;
        }
    }

 

后序遍历:

复杂一些,依次逆序打印所有节点的左子树的右边界,打印的时机放在步骤2的条件Ⅰ被触发的时候。

public void morrisPos(TreeNode root) {
        if (root == null)
            return;
        TreeNode cur1 = root;
        TreeNode cur2 = null;
        while (cur1 != null) {
            cur2 = cur1.left;
            if (cur2 != null) {
                while (cur2.right != null && cur2.right != cur1)
                    cur2 = cur2.right;
                if (cur2.right == null) {
                    cur2.right = cur1;
                    cur1 = cur1.left;
                    continue;
                } else {
                    cur2.right = null;
                    printEdge(cur1.left);
                }
            }
            cur1 = cur1.right;
        }
        printEdge(root);
    }

    public void printEdge(TreeNode root) {
        TreeNode tail = reverseEdge(root);
        TreeNode cur = tail;
        while (cur != null) {
            System.out.println(cur.val);
            cur = cur.right;
        }
        reverseEdge(tail);
    }

    public TreeNode reverseEdge(TreeNode from) {
        TreeNode pre = null;
        TreeNode next = null;
        while (from != null) {
            next = from.right;
            from.right = pre;
            pre = from;
            from = next;
        }
        return pre;
    }

 

全部代码含主函数

技术分享图片
package tools;

public class Morris {

    public class TreeNode {
        public int val;
        public TreeNode left;
        public TreeNode right;

        public TreeNode(int x) {
            this.val = x;
        }
    }

    public void morrisIn(TreeNode root) {
        if (root == null)
            return;
        TreeNode cur1 = root;
        TreeNode cur2 = null;
        while (cur1 != null) {
            cur2 = cur1.left;
            if (cur2 != null) {
                // 找到cur1左子树的最右节点
                while (cur2.right != null && cur2.right != cur1)
                    cur2 = cur2.right;
                // cur2.right == null 则往上链接
                if (cur2.right == null) {
                    cur2.right = cur1;
                    cur1 = cur1.left;
                    continue;
                }
                // cur2.right == cur1 则取消链接
                else {
                    cur2.right = null;
                }
            }
            System.out.println(cur1.val);
            cur1 = cur1.right;
        }
    }

    public void morrisPre(TreeNode root) {
        if (root == null)
            return;
        TreeNode cur1 = root;
        TreeNode cur2 = null;
        while (cur1 != null) {
            cur2 = cur1.left;
            if (cur2 != null) {
                while (cur2.right != null && cur2.right != cur1)
                    cur2 = cur2.right;
                if (cur2.right == null) {
                    cur2.right = cur1;
                    System.out.println(cur1.val);
                    cur1 = cur1.left;
                    continue;
                } else {
                    cur2.right = null;
                }
            } else {
                System.out.println(cur1.val);
            }
            cur1 = cur1.right;
        }
    }

    public void morrisPos(TreeNode root) {
        if (root == null)
            return;
        TreeNode cur1 = root;
        TreeNode cur2 = null;
        while (cur1 != null) {
            cur2 = cur1.left;
            if (cur2 != null) {
                while (cur2.right != null && cur2.right != cur1)
                    cur2 = cur2.right;
                if (cur2.right == null) {
                    cur2.right = cur1;
                    cur1 = cur1.left;
                    continue;
                } else {
                    cur2.right = null;
                    printEdge(cur1.left);
                }
            }
            cur1 = cur1.right;
        }
        printEdge(root);
    }

    public void printEdge(TreeNode root) {
        TreeNode tail = reverseEdge(root);
        TreeNode cur = tail;
        while (cur != null) {
            System.out.println(cur.val);
            cur = cur.right;
        }
        reverseEdge(tail);
    }

    public TreeNode reverseEdge(TreeNode from) {
        TreeNode pre = null;
        TreeNode next = null;
        while (from != null) {
            next = from.right;
            from.right = pre;
            pre = from;
            from = next;
        }
        return pre;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Morris m = new Morris();
        TreeNode t1 = m.new TreeNode(4);
        TreeNode t2 = m.new TreeNode(2);
        TreeNode t3 = m.new TreeNode(6);
        TreeNode t4 = m.new TreeNode(1);
        TreeNode t5 = m.new TreeNode(3);
        TreeNode t6 = m.new TreeNode(5);
        TreeNode t7 = m.new TreeNode(7);
        t1.left = t2;
        t1.right = t3;
        t2.left = t4;
        t2.right = t5;
        t3.left = t6;
        t3.right = t7;
        m.morrisPre(t1);
        m.morrisIn(t1);
        m.morrisPos(t1);
    }

}
Morris.java

 

以上是关于Morris遍历遍历二叉树的主要内容,如果未能解决你的问题,请参考以下文章

Morris遍历遍历二叉树

Morris 遍历二叉树

二叉树的遍历——Morris

预备知识:Morris二叉树遍历算法

488,二叉树的Morris中序和前序遍历

二叉树遍历高级算法之Morris---莫里斯算法