Morris方法遍历二叉树 Binary Tree Morris Traversal
通常,实现二叉树的前序(preorder)、中序(inorder)、后序(postorder)遍历有两个常用的方法:一是递归(recursive),二是使用栈实现的迭代版本(stack+iterative)。这两种方法都是O(n)的空间复杂度(递归本身占用stack空间或者用户自定义的stack),我在其他博客文章中有关于这些的实现。
假如有这样一个问题,实现二叉树的前中后序遍历,有两个要求:
- O(1)空间复杂度,即只能使用常数空间;
- 二叉树的形状不能被破坏(中间过程允许改变其形状)。
Morris Traversal方法可以做到这两点,与前两种方法的不同在于该方法只需要O(1)空间,而且同样可以在O(n)时间内完成。要使用O(1)空间进行遍历,最大的难点在于,遍历到子节点的时候怎样重新返回到父节点(假设节点中没有指向父节点的p指针),由于不能用栈作为辅助空间。为了解决这个问题,Morris方法用到了线索二叉树(threaded binary tree)的概念。在Morris方法中不需要为每个节点额外分配指针指向其前驱(predecessor)和后继节点(successor),只需要利用叶子节点中的左右空指针指向某种顺序遍历下的前驱节点或后继节点就可以了。
具体实现代买如下:
// Definition for a binary tree node.
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
import java.util.ArrayList;
import java.util.List;
// PreOrder Morris Traversal
// Time Complexity: O(n), n is the node number in the tree
// Space Complexity: O(1)
public class PreorderSolution {
public List<Integer> preorderTraversal(TreeNode root) {
ArrayList<Integer> res = new ArrayList<Integer>();
if(root == null)
return res;
TreeNode cur = root;
while(cur != null){
if(cur.left == null){
res.add(cur.val);
cur = cur.right;
}
else{
TreeNode prev = cur.left;
while(prev.right != null && prev.right != cur)
prev = prev.right;
if(prev.right == null){
res.add(cur.val);
prev.right = cur;
cur = cur.left;
}
else{
prev.right = null;
cur = cur.right;
}
}
}
return res;
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
// Inorder Morris Traversal
// Time Complexity: O(n), n is the node number in the tree
// Space Complexity: O(1)
public class InorderSolution {
public List<Integer> inorderTraversal(TreeNode root) {
ArrayList<Integer> res = new ArrayList<Integer>();
if(root == null)
return res;
TreeNode cur = root;
while(cur != null){
if(cur.left == null){
res.add(cur.val);
cur = cur.right;
}
else{
TreeNode prev = cur.left;
while(prev.right != null && prev.right != cur)
prev = prev.right;
if(prev.right == null){
prev.right = cur;
cur = cur.left;
}
else{
prev.right = null;
res.add(cur.val);
cur = cur.right;
}
}
}
return res;
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
// Morris PostOrder Traversal
//
// Time Complexity: O(n)
// Space Complexity: O(1)
public class PostorderSolution {
public List<Integer> postorderTraversal(TreeNode root) {
ArrayList<Integer> res = new ArrayList<Integer>();
if(root == null)
return res;
TreeNode dummyRoot = new TreeNode(-1);
dummyRoot.left = root;
TreeNode cur = dummyRoot;
while(cur != null){
if(cur.left == null)
cur = cur.right;
else{
TreeNode pre = cur.left;
while(pre.right != null && pre.right != cur)
pre = pre.right;
if(pre.right == null){
pre.right = cur;
cur = cur.left;
}
else{
pre.right = null;
reverseTraversal(cur.left, res);
cur = cur.right;
}
}
}
return res;
}
private void reverseTraversal(TreeNode node, ArrayList<Integer> res){
int start = res.size();
while(node != null){
res.add(node.val);
node = node.right;
}
int i = start, j = res.size() - 1;
while(i < j){
Integer t = res.get(i);
res.set(i, res.get(j));
res.set(j, t);
i ++;
j --;
}
}
}
本文参考:
http://www.cnblogs.com/AnnieKim/archive/2013/06/15/MorrisTraversal.html。