1. 程式人生 > 其它 >二叉樹的前序遍歷之Morris

二叉樹的前序遍歷之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

第五步,

我們獲取到樹的根D,判斷D的左子樹,如果D的左子樹為空,那麼將D放入陣列,同時將根指向A

第六步,我們獲取到樹的根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;
}

  

是春風,是餘暉, 是一道曙光, 是未來可期。

手敲不易,點個讚唄