二叉樹前中後序遍歷非遞歸實現(JavaScript)

二叉樹使用遞歸實現前中後序遍歷是很是容易的,本文給出非遞歸實現前中後序遍歷的方法,核心的思想是使用一個棧,經過迭代來模擬遞歸的實現過程javascript

下面實現中root表明二叉樹根節點,每一個節點都具備left,right兩個指針,分別指向當前節點左右子樹,一個val屬性表明當前節點的值java

前序遍歷(preorderTraversal)

const preorderTraversal = function(root) {
    const stack = [], res = []
    root && stack.push(root)
    // 使用一個棧stack,每次首先輸出棧頂元素,也就是當前二叉樹根節點,以後依次輸出二叉樹的左孩子和右孩子
    while(stack.length > 0) {
        let cur = stack.pop()
        res.push(cur.val)
        // 先入棧的元素後輸出,因此先入棧當前節點右孩子,再入棧左孩子
        cur.right && stack.push(cur.right)
        cur.left && stack.push(cur.left)
    }
    return res
};
複製代碼

中序遍歷(inorderTraversal)

第一種方法

const inorderTraversal = function(root) {
    const res = [], stack = []
    while(root || stack.length) {
        // 中序遍歷,首先迭代左孩子,左孩子依次入棧
        if(root.left) {
            stack.push(root)
            root = root.left
        // 若是左孩子爲空了,輸出節點,去右孩子中迭代,
        } else if(root.right) {
            res.push(root.val)
            root = root.right
        // 若是左右孩子都爲空了,輸出當前節點,棧頂元素出棧,也就是回退到上一層,此時置空節點左孩子,防止while循環重複進入
        } else if(!root.left && !root.right) {
            res.push(root.val)
            root = stack.pop()
            root && (root.left = null)
        }
    }
    return res
};
複製代碼

第二種方法(第一種優化)

咱們在上一種方法裏,條件判斷root.left,root.right,其實咱們能夠只考慮當前節點node,這樣咱們只須要判斷node是否存在,簡化代碼node

const inorderTraversal = function(root) {
    const res = [], stack = []
    let node = root;
    while (stack.length > 0 || node !== null) {
        // 這裏用當前節點node是否存在,簡化代碼,
        if (node) {
            stack.push(node);
            node = node.left
        } else {
            node = stack.pop();
            res.push(node.val);
            node = node.right;
        }
    }
    return res;
};
複製代碼

後序遍歷(postorderTraversal)

第一種方法

// 1, 先依次遍歷左孩子, 在棧中依次記錄,當左孩子爲空時,遍歷到葉子節點 //跳回上一層節點, 爲防止while循環重複進入,將上一層左孩子置爲空
// 2, 接着遍歷右孩子, 在棧中依次記錄值,當右孩子爲空時, 遍歷到葉子節點
// 跳回上一層節點, 爲防止while循環重複進入,將上一層右孩子置爲空
const postorderTraversal = function(root) {
    let res = [], stack = []
    while (root || stack.length) {
        if (root.left) {
            stack.push(root)
            root = root.left
        } else if (root.right) {
            stack.push(root)
            root = root.right
        } else {
            res.push(root.val)
            root = stack.pop()
            if (root && root.left) root.left = null
            else if (root && root.right) root.right = null
        }
    }
    return res
};
複製代碼

第二種方法(逆序思惟)

再回頭看看前序遍歷的代碼,實際上後序遍歷和前序遍歷是一個逆序過程數組

// 結果數組中依次進入的是節點的左孩子,右孩子,節點自己,注意使用的是
// unshift,與前序遍歷push不一樣,每次數組頭部添加元素,實際上就是前序 遍歷的逆序過程
const postorderTraversal = function(root) {
    const res = [], stack = []
    while (root || stack.length) {
        res.unshift(root.val)
        root.left && stack.push(root.left)
        root.right && stack.push(root.right)
        root = stack.pop()
    }
    return res
};
複製代碼

第三種方法(逆序思惟的另外一種寫法)

// 和前序遍歷區別在於,結果數組res中入棧順序是當前節點,右孩子,左孩子,最後
// 使用js數組reverse方法反轉(逆序),使得輸出順序變爲左孩子,右孩子,當前節點,實現後序遍歷
const postorderTraversal = function(root) {
    let stack = [], res = []
    root && stack.push(root)
    while(stack.length > 0) {
        let cur = stack.pop()
        res.push(cur.val)
        cur.left && stack.push(cur.left)
        cur.right && stack.push(cur.right)
    }
    return res.reverse()
};
複製代碼

本文詳細介紹了二叉樹前中後序遍歷的非遞歸實現,核心是藉助一個棧stack,使用迭代的方式模擬遞歸過程markdown

相關文章
相關標籤/搜索