通常,我们遍历一颗二叉树都会采用递归的方式,即前序遍历、中序遍历和后序遍历,这三种方法的时间复杂度为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;
}
}