遍历二叉树的递归方法使用了函数栈,非递归方法使用了申请的栈,
两者的额外空间都与树的高度有关,所以空间复杂度为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);
}
}