zoukankan      html  css  js  c++  java
  • 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

     

  • 相关阅读:
    CSS3 背景
    CSS3 边框
    CSS3中的transform变形
    兼容IE与firefox火狐的回车事件(js与jquery)
    JS相关链接
    JS操作DOM元素属性和方法
    用js给html设置style
    JavaScript数学函数(一)
    [JS] 如何清空file input框 [整理]
    未在本地计算机上注册Microsoft.ACE.OLEDB.12.0提供程序(Oledb)
  • 原文地址:https://www.cnblogs.com/wangkaipeng/p/9813856.html
Copyright © 2011-2022 走看看