Morris遍歷二叉樹

通常,我們遍歷一顆二叉樹都會採用遞歸的方式,即前序遍歷、中序遍歷和後序遍歷,這三種方法的時間複雜度爲O(N),空間複雜度爲O(logN);而Morris算法遍歷一顆二叉樹的時間複雜度爲O(2N),空間複雜度爲O(1).可以想象這是一件很吸引人的特性。
二叉樹是一種非線性的結構,而前面說的三種遍歷方法實際上是將非線性轉換成線性的過程。即將一個樹轉變成一個鏈表的過程。那麼除了鏈表的頭和尾外,每個中間點都有一個唯一的前驅和後驅。

Morris算法實施過程中實際上包含了兩步,(以中序遍歷爲例子),第一步,找到當前節點的中序遍歷的直接前驅,也就是當前節點的左兒子的右子樹的最後一個節點,然後將最後一個節點的右指針指向當前節點。目的是當遍歷完左子樹後還能回到當前節點。第二步,迭代訪問左子樹,當訪問到左兒子爲null時,訪問當前節點,下一步訪問右兒子。此時右兒子一定不是null,原因在於第一步的時候,實際上已經將右兒子指向了它的中序後繼p。而這也表示p的左子樹已經遍歷完了。此時訪問p,然後訪問p的右子樹。

代碼如下:

package com.dacas;

import java.util.LinkedList;
import java.util.List;

/**
 * Created by dave on 2016/6/12.
 */
public class main {
    public static void main(String[] args){
        TreeNode root = generateTreeNode();
        List<TreeNode> list1 = inOrderWithMorris(root);
        System.out.println("inOrderWithMorris:");
        showInfo(list1);
        List<TreeNode> list2 = preOrderWithMoris(root);
        System.out.println("preOrderWithMorris:");
        showInfo(list2);
        List<TreeNode> list3 = inOrder(root);
        System.out.println("inOrder:");
        showInfo(list3);
        List<TreeNode> list4 = preOrder(root);
        System.out.println("preOrder:");
        showInfo(list4);
    }
    private static List<TreeNode> inOrderWithMorris(TreeNode root){
        List<TreeNode> lists = new LinkedList<>();
        TreeNode p = root,tmp;

        while(p != null){
            if(p.left == null){
                lists.add(p);
                p = p.right;
            }else{
                tmp = p.left;
                while(tmp.right != null && tmp.right != p){
                    tmp = tmp.right;
                }
                if(tmp.right == null)//first visit and the left need be visited
                {
                    tmp.right = p;
                    p = p.left;
                }else{//second visit node
                    lists.add(p);
                    tmp.right = null;//restore tree structure
                    p = p.right;//next need to visit right subtree
                }
            }
        }
        return lists;
    }
    private static List<TreeNode> preOrderWithMoris(TreeNode root){
        List<TreeNode> lists = new LinkedList<>();
        TreeNode p = root,tmp;

        while(p != null){
            if(p.left == null){
                lists.add(p);
                p = p.right;
            }else{
                tmp = p.left;
                while(tmp.right != null && tmp.right != p)
                    tmp = tmp.right;
                if(tmp.right == null){//visit root node
                    lists.add(p);
                    tmp.right = p;
                    p = p.left;
                }else{
                    tmp.right = null;
                    p = p.right;
                }
            }
        }
        return lists;
    }
    private static List<TreeNode> inOrder(TreeNode root){
        List<TreeNode> lists = new LinkedList<>();
        inOrderRecurse(lists,root);
        return lists;
    }
    private static void inOrderRecurse(List<TreeNode> lists,TreeNode root){
        if(root == null)
            return;
        inOrderRecurse(lists,root.left);
        lists.add(root);
        inOrderRecurse(lists, root.right);
    }
    private static List<TreeNode> preOrder(TreeNode root){
        List<TreeNode> lists = new LinkedList<>();
        preOrderRecurse(lists, root);
        return lists;
    }
    private static void preOrderRecurse(List<TreeNode> lists,TreeNode root){
        if(root == null)
            return;
        lists.add(root);
        preOrderRecurse(lists, root.left);
        preOrderRecurse(lists,root.right);
    }
    private static void showInfo(List<TreeNode> lists){
        for(TreeNode node:lists){
            System.out.print(node.val+" ");
        }
        System.out.println();
    }
    //創建包含16個節點的
    private static TreeNode generateTreeNode(){
        TreeNode root = new TreeNode(1,new TreeNode(2),new TreeNode(3));
        TreeNode p = root.left;
        p.left = new TreeNode(4,new TreeNode(7),new TreeNode(8));
        p.right = new TreeNode(5,new TreeNode(9),null);

        p = root.right;
        p.left=new TreeNode(6,null,new TreeNode(10));
        return root;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章