Morris遍歷時間復雜度為O(n),空間復雜度為O(1)。可以通過Morris遍歷完成先序中序后續遍歷。
在Morris遍歷中,若當前節點有左孩子,則會訪問該節點兩次。若無左孩子,則會訪問該節點一次。至於遍歷順序與遞歸遍歷類似。遍歷順序由在第幾次訪問該節點時輸出決定。
對於有左孩子的節點,第一次訪問到便輸出,為先序遍歷。第二次訪問時輸出為中序遍歷。
后序遍歷為:第二次訪問到某一節點是,逆序的打印其左子樹的最右邊界。最后單獨逆序打印整棵樹的右邊界。
Morris遍歷規則:
1.對於當前節點cur,若cur無左孩子,則cur=cur.right。
2.如果cur有左孩子,找到cur左子樹最右節點,記為mostright。
2.1如果mostright右孩子為空,則mostright.right=cur。cur向左移動。(此時為第一次訪問該節點)
2.2如果mostright右孩子為cur,則mostright.right=null。cur向右移動(此時為第二次訪問該節點)
對於以下二叉樹:
訪問順序為:1 2 4 2 5 1 3 6 3 7
先序遍歷順序:1 2 4 5 3 6 7(所有節點均第一次訪問時輸出)
中序遍歷順序:4 2 5 1 3 6 7(有左孩子的節點第二次訪問時輸出)
后序遍歷順序:4 5 2 6 7 3 1(有左孩子的節點第二次訪問時,逆序輸出左子樹的右邊界,最后加上整棵樹的逆序右邊界。對於2,輸出4,對於1輸出5,2 對於3,輸出6,最后輸出7 3 1)
先序遍歷:
package Leetcode; public class Morris { public void preOrder(TreeNode head){ if(head==null){ return; } TreeNode cur =head; TreeNode mostRight ; while (cur!=null){ if(cur.left==null){ System.out.println(cur.val); cur = cur.right; }else{ mostRight = cur.left; //尋找左子樹最右節點 while (mostRight.right!=null&&mostRight.right!=cur){ mostRight = mostRight.right; } if(mostRight.right==null){ //此時為第一次訪問該節點 System.out.println(cur.val); mostRight.right = cur; cur = cur.left; }else{ //此時為第二次訪問該節點 mostRight.right=null; cur = cur.right; } } } } }
中序遍歷:
package Leetcode; public class Morris { public void inOrder(TreeNode head){ if(head==null){ return; } TreeNode cur =head; TreeNode mostRight ; while (cur!=null){ if(cur.left==null){ System.out.println(cur.val); cur = cur.right; }else{ mostRight = cur.left; //尋找左子樹最右節點 while (mostRight.right!=null&&mostRight.right!=cur){ mostRight = mostRight.right; } if(mostRight.right==null){ //此時為第一次訪問該節點 mostRight.right = cur; cur = cur.left; }else{ //此時為第二次訪問該節點 System.out.println(cur.val); mostRight.right=null; cur = cur.right; } } } } public static void main(String[] args) { Morris m =new Morris(); TreeNode t1 = new TreeNode(1); TreeNode t2 = new TreeNode(2); TreeNode t3 = new TreeNode(3); TreeNode t4 = new TreeNode(4); TreeNode t5 = new TreeNode(5); TreeNode t6 = new TreeNode(6); TreeNode t7 = new TreeNode(7); t1.left = t2; t1.right = t3; t2.left= t4; t2.right= t5; t3.left= t6; t3.right= t7; m.preOrder(t1); } }
后序遍歷:
package Leetcode; import java.util.Stack; public class Morris { public void postOrder(TreeNode head){ if(head==null){ return; } TreeNode cur =head; TreeNode mostRight ; while (cur!=null){ if(cur.left==null){ cur = cur.right; }else{ mostRight = cur.left; //尋找左子樹最右節點 while (mostRight.right!=null&&mostRight.right!=cur){ mostRight = mostRight.right; } if(mostRight.right==null){ //此時為第一次訪問該節點 mostRight.right = cur; cur = cur.left; }else{ //此時為第二次訪問該節點 mostRight.right=null; sout(cur.left); cur = cur.right; } } } sout(head); } //逆序輸出當前節點左子樹的右邊界 private void sout(TreeNode node) { Stack<Integer> stack = new Stack<>(); while (node!=null){ stack.add(node.val); node = node.right; } while (!stack.isEmpty()){ System.out.println(stack.pop()); } } }