二叉樹(一): 遍歷

什麼是二叉樹

在計算機科學中,二叉樹(英語:Binary tree)是每一個節點最多隻有兩個分支(即不存在分支度大於2的節點)的樹結構。一般分支被稱做「左子樹」或「右子樹」。二叉樹的分支具備左右次序,不能隨意顛倒。
二叉樹的第i層至多有2^{i-1}個結點;
深度爲k的二叉樹至多有2^k-1個結點;
對任何一棵二叉樹T,若樹葉總數爲 n_0,分支度爲2的總數爲n_2,則n_0=n_2+1。
一棵深度爲k,且有2^k-1個節點稱之爲滿二叉樹;
深度爲k,有n個節點的二叉樹,當且僅當其每個節點都與深度爲k的滿二叉樹中,序號爲1至n的節點對應時,稱之爲徹底二叉樹。

特殊類型

徹底二叉樹 完美二叉樹
總節點k 2^ (h − 1) <= k <= 2^(h − 1) k = 2^h − 1
樹高h h = l o g 2 k + 1 h = l o g 2 ( k + 1 )

深度優先遍歷

英文縮寫爲DFS即Depth First Search。 在深度優先級中,咱們但願從根結點訪問最遠的結點。前序,中序和後序遍歷都是深度優先遍歷的特例。前端

先來看一張圖, 一眼瞭解這三種遍歷:node

做爲前端, 我是確定先用 JS 來實現這些遍歷的, 先定義一個二叉樹的結構:git

const nodes = {
    node: 6,
    left: {
        node: 5,
        left: {
            node: 4
        },
        right: {
            node: 3
        }
    },
    right: {
        node: 2,
        right: {
            node: 1
        }
    }
}

先序遍歷

let list = []

function preOrder(node) {
    if (!(node == null)) {
        list.push(node.node);
        preOrder(node.left);
        preOrder(node.right);
    }
}

執行: preOrder(nodes)github

打印 list 結果: [6, 5, 4, 3, 2, 1]算法

中序遍歷

let list = []

function inOrder(node) {
    if (!(node == null)) {
        inOrder(node.left);
        list.push(node.node);
        inOrder(node.right);
    }
}

執行: inOrder(nodes)segmentfault

打印 list 結果: [4, 5, 3, 6, 2, 1]app

後序遍歷

let list = []

function postOrder(node) {
    if (!(node == null)) {
        postOrder(node.left);
        postOrder(node.right);
        list.push(node.node);
    }
}

執行: postOrder(nodes)post

打印 list 結果: [4, 3, 5, 1, 2, 6]優化

廣度優先遍歷

英文縮寫爲BFS即Breadth FirstSearch。其過程檢驗來講是對每一層節點依次訪問,訪問完一層進入下一層,並且每一個節點只能訪問一次。 廣度遍歷即咱們尋常所說的層次遍歷。spa

const levelOrder = function (root) {
    if (root == null) {
        return []
    }
    let result = []
    let queue = [root]
    while (queue.length) {
        // 每一層的節點數
        let level = queue.length
        let currLevel = []
        // 每次遍歷一層元素
        for (let i = 0; i < level; i++) {
            // 當前訪問的節點出隊
            let curr = queue.shift()
            curr.left && queue.push(curr.left)
            curr.right && queue.push(curr.right)
            currLevel.push(curr.node)
        }
        result.push.apply(result, currLevel)
    }
    return result
}

打印結果: [6, 5, 2, 4, 3, 1]
currLevel 中的打印: [6] [5,2] [4,3,1]

這個思路比較好理解, 卻是還不夠好

優化

const levelOrder = function (root) {
    if (!root) return [];
    let queue = [root];
    let res = [];
    while (queue.length) {
        let item = queue.shift();
        res.push(item.node);
        item.left && queue.push(item.left);
        item.right && queue.push(item.right);
    }
    return res;
}

打印結果: [6, 5, 2, 4, 3, 1]

這種算法只是用了一個隊列, 效果較好

總結

這是二叉樹相關的第一篇, 比較基礎, 後續還會更新

倉庫地址: https://github.com/Grewer/notes

參考:

相關係列

相關文章
相關標籤/搜索