morris遍历的优点在于节省空间,因为不需要递归。

数据结构与算法-morris遍历_数据结构

public class MorrisTraversal {
    public static void main(String[] args) {
        Node head = new Node(4);
        head.left = new Node(2);
        head.right = new Node(6);
        head.left.left = new Node(1);
        head.left.right = new Node(3);
        head.right.left = new Node(5);
        head.right.right = new Node(7);

        morris(head);
        morris2(head);
        morrisPre(head);
        morrisMiddle(head);
        morrisPos(head);
    }

    public static class Node{
        public int value;
        Node left;
        Node right;

        public Node(int data){
            this.value = data;
        }
    }

    public static void morris(Node head){
        if(head == null){
            return ;
        }

        Node cur = head;
        Node mostRight = null;
        boolean isRighNull = true;
        while(cur != null){
            System.out.print(cur.value+"  ");
            if(cur.left == null){ // 如果cur没有左孩子,cur向右移动
                cur = cur.right;
            }else{
                    mostRight = cur.left;
                    isRighNull = true;
                    while (mostRight.right != null) {
                        if(mostRight.right == cur){
                            isRighNull = false;
                            break;
                        }
                        mostRight = mostRight.right;
                    }

                    if (isRighNull) {
                        mostRight.right = cur;
                        cur = cur.left;
                    }else{
                        mostRight.right = null;
                        cur = cur.right;
                    }
            }
        }
        System.out.println();
    }

    public static void morris2(Node head){
        if(head == null){
            return ;
        }

        Node cur = head;
        Node mostRight = null;
        while(cur != null){
            System.out.print(cur.value+"  ");
            mostRight = cur.left;
            if(mostRight != null){// 如果cur没有左孩子,cur向右移动
                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;
                }
            }
                cur = cur.right;
        }
        System.out.println();
    }

    /*
    *  先序遍历
    *   1.如果当前节点没有左节点,就打印当前节点的值
    *   2.如果当前节点有左节点,第一次到达该节点时,就打印此节点
    * */
    public static void morrisPre(Node head){
        if(head == null){
            return ;
        }

        Node cur = head;
        Node mostRight = null;
        while(cur != null){
            //System.out.print(cur.value+"  ");
            mostRight = cur.left;
            if(mostRight != null){// 如果cur没有左孩子,cur向右移动
                while (mostRight.right != null && mostRight.right != cur){
                    mostRight = mostRight.right;
                }
                if(mostRight.right == null){
                    System.out.print(cur.value+" ");
                    mostRight.right = cur;
                    cur = cur.left;
                    continue;
                }else{
                    mostRight.right = null;
                }
            }else{
                System.out.print(cur.value+" ");
            }
            cur = cur.right;
        }
        System.out.println();
    }

    /*
     *  中序遍历
     *   1.如果当前节点没有左节点,就打印当前节点的值
     *   2.如果当前节点有左节点,第二次到达该节点时,就打印此节点
     * */
    public static void morrisMiddle(Node head){
        if(head == null){
            return ;
        }

        Node cur = head;
        Node mostRight = null;
        while(cur != null){
            //System.out.print(cur.value+"  ");
            mostRight = cur.left;
            if(mostRight != null){// 如果cur没有左孩子,cur向右移动
                while (mostRight.right != null && mostRight.right != cur){
                    mostRight = mostRight.right;
                }
                if(mostRight.right == null){
                    mostRight.right = cur;
                    cur = cur.left;
                    continue;
                }else{
                    System.out.print(cur.value+" ");
                    mostRight.right = null;
                }
            }else{
                System.out.print(cur.value+" ");
            }
            cur = cur.right;
        }
        System.out.println();
    }

    /*
     *  后序遍历
     *   1.如果当前节点有左节点,第二次到达该节点时,逆序打印该节点的左节点的右边界
     *   2.最后打印整棵树的右边界
     * */
    public static void morrisPos(Node head){
        if(head == null){
            return ;
        }

        Node cur = head;
        Node mostRight = null;
        while(cur != null){
            //System.out.print(cur.value+"  ");
            mostRight = cur.left;
            if(mostRight != null){// 如果cur没有左孩子,cur向右移动
                while (mostRight.right != null && mostRight.right != cur){
                    mostRight = mostRight.right;
                }
                if(mostRight.right == null){
                    mostRight.right = cur;
                    cur = cur.left;
                    continue;
                }else{
                    //System.out.print(cur.value+" ");
                    mostRight.right = null;
                    printEdte(cur.left); // 第二次到达该节点时,逆序打印该节点的左节点的右边界
                }
            }
            cur = cur.right;
        }
        printEdte(head);
        System.out.println();
    }

    public static void printEdte(Node head){
        Node tail = reverseEdge(head); // 反转链表,形成逆序
        Node cur = tail;
        while(cur != null){
            System.out.print(cur.value+" ");
            cur = cur.right;
        }
        reverseEdge(tail);
    }

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