1. 程式人生 > >Morris遍歷遍歷二叉樹

Morris遍歷遍歷二叉樹

span out 葉子 while alt left pri 空間 pre

遍歷二叉樹的遞歸方法使用了函數棧,非遞歸方法使用了申請的棧,

兩者的額外空間都與樹的高度有關,所以空間復雜度為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遍歷遍歷二叉樹