Morris遍歷遍歷二叉樹
阿新 • • 發佈:2018-10-19
span out 葉子 while alt left pri 空間 pre
遍歷二叉樹的遞歸方法使用了函數棧,非遞歸方法使用了申請的棧,
兩者的額外空間都與樹的高度有關,所以空間復雜度為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);
}
}
Morris.java
Morris遍歷遍歷二叉樹