二叉樹的前序遍歷之Morris
之前我們介紹了二叉樹前序排序的兩種方法,一種是遞迴,一種是迭代。這兩種沒有什麼大的差別。今天我們帶來了一種Morris遍歷
Morris 遍歷的核心思想是利用樹的大量空閒指標,實現空間開銷的極限縮減
其前序遍歷規則總結如下:
1,新建臨時樹,令該節點為樹的根;
2,如果當前根的左子樹為空,將當前根放入陣列,並將當前根的右子樹更新為樹的根;
3,如果當前根的左子樹不為空,獲取到當前根的左子樹:
3.1, 迴圈遍歷當前根的左子樹的所有右子樹,獲取到最後一個不等於根的右子樹
3.1, 如果獲取到的右子樹為空,將根節點放入陣列,然後將根賦值給遍歷獲取到的右子樹的右子樹。
3.2, 如果獲取到的右子樹不為空,將獲取到的右子樹的右子樹刪除,同時將根的右子樹更新為樹的根
重複步驟 2 和步驟 3,直到遍歷結束。
看到這裡如果有一點點懵的話就看一下下面的圖,我會一步一步的將實現過程給畫出來。
第一步,我們獲取到樹的根F,然後獲取F的左子樹,如果左子樹為空,我們就將F放入陣列,然後獲取樹的右子樹更新為樹的根。
這裡左子樹不為空,我們第一步拿到樹的左子樹B,然後遍歷B的所有右子樹,一直遍歷到右子樹為空並且右子樹不等於當前根的情況,這裡我們B本來就沒有右子樹,所以直接拿到B。
當B的右子樹為空,我們將F放入陣列。然後將F放入B的右子樹。
根節點指向B
第二步,我們獲取到樹的根 B,判斷B的左子樹,如果左子樹為空,我們將就將B 放入陣列,同時將根指向 F
第三步,我們獲取到樹的根F,判斷F的左子樹是否為空,這裡樹的左子樹不為空,所以拿到樹的左子樹B ,然後遍歷B的所有右子樹,一直遍歷到右子樹為空並且右子樹不等於根的情況。
這裡B的右子樹是等於根的,所以走恢復二叉樹的邏輯,將B的右子樹 清空,同時將根指向根的右子樹 A
第四步,我們獲取到樹的根A,判斷A的左子樹是否為空,這裡樹的左子樹不為空,所以拿到樹的左子樹D,然後遍歷D的所有右子樹,一直遍歷到右子樹為空並且右子樹不等於當前根的情況,這裡我們的D本來就沒有右子樹,所以直接拿到D ,因為D的右子樹為空,那麼我們將根A放入到陣列,將根A放入到D的右子樹。根節點指向D
第五步,
第六步,我們獲取到樹的根A,判斷A的左子樹是否為空,這裡A的左子樹是不為空的,所以拿到A的左子樹D,然後遍歷D的所有右子樹,一直到右子樹為空並且右子樹不等於根,這裡D的右子樹等於根,我們走恢復二叉樹邏輯,將D的右子樹A刪除,然後將根指向A的右子樹C
第七步,我們獲取到樹的根C,判斷C的左子樹是否為空,這裡C的左子樹為空,那麼將C放入陣列,同時將根指向C的右子樹,C的右子樹為空遍歷結束
經過我們一步一步的拆解,是不是已經感覺這個排序也超級簡單呢,現在上程式碼
public static void main(String[] args) { Solution solution = new Solution(); TreeNode t = new TreeNode("F", new TreeNode("B",null,null), new TreeNode("A", new TreeNode("D",null,null), new TreeNode("C",null,null))); System.out.println(Morris_PreOrder(t)); } public static List<String> Morris_PreOrder(TreeNode root) { List<String> res = new ArrayList<>(); if(root == null){ return res; } TreeNode cur = root; while(cur != null) { if(cur.left == null) { res.add(cur.val); cur = cur.right; } else { TreeNode tmp = cur.left; while(tmp.right != null && tmp.right != cur){ tmp = tmp.right; } if(tmp.right == null) { res.add(cur.val); //輸出當前節點 tmp.right = cur; //將當前根節點賦值給 最右子樹的右子樹 cur = cur.left; } else { tmp.right = null; //恢復二叉樹 cur = cur.right; } } } return res; }
是春風,是餘暉, 是一道曙光, 是未來可期。
手敲不易,點個讚唄