通常,我們遍歷一顆二叉樹都會採用遞歸的方式,即前序遍歷、中序遍歷和後序遍歷,這三種方法的時間複雜度爲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;
}
}