「種樹專業戶」「樹」業有專攻

圖怪獸_2bd02daed73e352d21a854313ff206a5_23114.png
觀感度:🌟🌟🌟🌟🌟前端

口味:螞蟻上樹node

烹飪時間:10mingit

本文已收錄在 Github github.com/Geekhyt,感謝Star。

周樹人先生曾經說過:學好樹,數據結構與算法你就掌握了一半!github

食堂老闆(童歐巴):就算咱們做爲互聯網浪潮中的葉子結點,也須要有不自量力的精神,就算不自量力是自不量力。由於就算終其一輩子只是個普通人,但你總不能爲了成爲一個普通人而終其一輩子吧。算法

今日菜譜,螞蟻上樹,下面介紹一下演員。數據庫

樹的相關名詞科普

  • 根節點
  • 葉子節點
  • 父節點
  • 子節點
  • 兄弟節點
  • 高度
  • 深度

A 是 根節點。C、D、F、G 是 葉子節點。A 是 B 和 E 的 父節點。B 和 E 是 A 的 子節點。B、E 之間是 兄弟節點高度、深度、層 如上圖所示。爲了方便理解記憶,高度 就是擡頭看,深度 就是低頭看。與 高度、深度 不一樣, 類比盜夢空間裏的樓,樓都是從 1 層開始計算,盜夢空間中的樓顛倒過來,從上往下。數組

二叉樹 Binary Tree

每一個節點最多有兩個子節點,也就是 左子節點右子節點數據結構

滿二叉樹 Full Binary Tree

葉子節點全都在最底層,除了葉子節點以外,每一個節點都有左右兩個子節點。上文中的圖就是滿二叉樹。post

徹底二叉樹 Complete Binary Tree

葉子節點都在最底下兩層,最後一層的葉子節點都靠左排列,而且除了最後一層,其餘層的節點個數都要達到最大。性能

堆其實就是一種徹底二叉樹,通常採用的存儲方式是數組。

採用數組存儲徹底二叉樹,無須像鏈式存儲同樣額外存儲左右子節點的指針,能夠節省內存。

二叉樹的遍歷

  • 前序遍歷:先打印當前節點,再打印當前節點的左子樹,最後打印當前節點的右子樹 (ABCDEFG)
  • 中序遍歷:先打印當前節點的左子樹,再打印當前節點,最後打印當前節點的右子樹 (CBDAFEG)
  • 後序遍歷:先打印當前節點的左子樹,再打印當前節點的右子樹,最後打印當前節點 (CDBFGEA)
// 前序遍歷
const preorderTraversal = function(root) {
    const result = [];
    function pushRoot(node) {
        if (node != null) {
            result.push(node.val);
            if (node.left != null) {
                pushRoot(node.left);
            }
            if (node.right != null){ 
                pushRoot(node.right);
            } 
        }
    }
    pushRoot(root);
    return result;
};
// 中序遍歷
const inorderTraversal = function(root) {
    const result = [];
    function pushRoot(node) {
        if (node != null) {
            if (node.left != null) {
                pushRoot(node.left);
            }
            result.push(node.val);
            if (node.right != null){ 
                pushRoot(node.right);
            } 
        }
    }
    pushRoot(root);
    return result;
};
// 後序遍歷
const postorderTraversal = function(root) {
    const result = [];
    function pushRoot(node) {
        if (node != null) {
            if (node.left != null) {
                pushRoot(node.left);
            }
            if (node.right != null){ 
                pushRoot(node.right);
            }
            result.push(node.val);
        }
    }
    pushRoot(root);
    return result;
};

複雜度分析

  • 時間複雜度: O(n)
  • 空間複雜度:最壞狀況爲 O(n),平均狀況爲 O(logn)

二叉查找樹 Binary Search Tree

又稱二叉排序樹、二叉搜索樹。

中序遍歷二叉查找樹,能夠輸出有序的數據序列,時間複雜度是 O(n),很是高效。

二叉查找樹中的任意一個節點,左子樹中的每一個節點的值,都小於這個節點的值,而右子樹節點的值都大於這個節點的值。

在二叉查找樹中,查找、插入、刪除等不少操做的時間複雜度都跟樹的高度成正比。兩個極端狀況的時間複雜度分別是 O(n)O(logn),分別對應二叉樹退化成鏈表的狀況和徹底二叉樹的狀況。

極端狀況下複雜度退化並非咱們想要的,因此咱們須要設計一種平衡二叉查找樹。平衡二叉查找樹的高度接近 logn,因此查找、插入、刪除操做的時間複雜度也比較穩定,是 O(logn)

AVL 樹 Adelson-Velsky-Landis Tree

AVL 樹 是最早被髮明的平衡二叉查找樹(以發明者的名字來進行的命名),它定義任何節點的左右子樹高度相差不超過 1,而且左右兩個子樹都是一棵平衡二叉樹。

AVL 樹是一種高度平衡的二叉查找樹。雖然查找效率高,可是爲了維持高度平衡,插入、刪除操做時都須要進行調整(左旋,右旋),須要付出很大的維持成本。

紅黑樹 Red-balck Tree

紅黑樹能夠被稱爲「網紅樹」了,它的出場率相比其餘的樹要高出一個天際線。與 AVL 樹不一樣,紅黑樹只是作到了近似平衡,並非嚴格意義上的平衡。因此在維護平衡付出的成本上比 AVL 樹要低,查找、插入、刪除等操做的性能都比較穩定,時間複雜度都是 O(logn)

一棵合格的紅黑樹應該知足:

  • 每一個結點或紅或黑
  • 根節點是黑色
  • 每一個葉子節點都是黑色的空節點(葉子節點不存儲數據)
  • 相鄰的節點不能同時爲紅色,紅黑相隔
  • 每一個節點,從該節點到達其可達葉子節點的全部路徑,都包含相同數目的黑色節點

紅黑樹在工程上有着大量的應用,由於工程上對性能的穩定性要求是很高的。正由於紅黑樹的性能比較穩定,它扛起了工程應用上的大旗。

Trie 樹

Google、百度一類的搜索引擎強大的關鍵詞提示功能的背後,最基本的原理就 Trie 樹,經過空間換時間,利用字符串的公共前綴,下降查詢的時間以提升效率。除此以外,還有不少應用,好比:IP 路由中使用了 Trie 樹的最長前綴匹配算法,利用轉發表選擇路徑以及 IDE 中的智能提示等。

Trie 樹 是一棵非典型的多叉樹模型,它和通常的多叉樹不一樣,咱們能夠對比一下它們結點的數據結構設計。通常的多叉樹結點中包含結點值和指向子結點的指針。而 Trie 樹的結點中包含的是該結點是不是一個串的結束,以及字母映射表。經過字母映射表咱們能夠經過一個父結點來獲取它全部子結點的值。

在 Trie 樹 中查找字符串的時間複雜度是 O(k),k 是要查找的字符串長度。

上圖中的 Trie 樹由 5 個單詞構成,分別是 color、coat、city、hi、hot。根結點的值爲空。

LeetCode 208.實現 Trie 樹

class Trie {
  constructor() {
    this.root = {};
  }
  insert(word) {
    let curr = this.root;
    word.split('').forEach(ch => (curr = curr[ch] = curr[ch] || {}));
    curr.isWord = true;
  }
  traverse(word) {
    let curr = this.root;
    for (let i = 0; i < word.length; i++) {
      if (!curr) return null;
      curr = curr[word[i]];
    }
    return curr;
  }
  search(word) {
    let node = this.traverse(word);
    return !!node && !!node.isWord;
  }
  startsWith(word) {
    return !!this.traverse(word);
  }
}

B+ 樹

咱們知道,將索引存儲在內容中,查詢速度是比存儲在磁盤中快的。可是當數據量很大的狀況下,索引也隨之變大。內存是有限的,咱們不得不將索引存儲在磁盤中。那麼,如何提高從磁盤中讀取的效率就成了工程上的關鍵之一。

大部分關係型數據庫的索引,好比 MySQL、Oracle,都是用 B+ 樹來實現的。B+ 樹比起紅黑樹更適合構建存儲在磁盤中的索引。B+ 樹是一個多叉樹,在相同個數的數據構建索引時,其高度要低於紅黑樹。當藉助索引查詢數據的時,讀取 B+ 樹索引,須要更少的磁盤 IO 次數。

一個 m 階的 B 樹知足以下特徵:

  • 每一個節點中子節點的個數 k 知足 m > k > m/2,根節點的子節點個數能夠不超過 m/2
  • 經過雙向鏈表將葉子節點串聯在一塊兒,方便按區間查找
  • m 叉樹只存儲索引,並不真正存儲數據
  • 通常狀況,根節點被存儲在內存中,其餘節點存儲在磁盤中

參考

  • 《數據結構與算法之美》 王爭

❤️愛心三連擊

1.看到這裏了就點個贊支持下吧,你的是我創做的動力。

2.關注公衆號前端食堂,你的前端食堂,記得按時吃飯

3.本文已收錄在前端食堂Github github.com/Geekhyt,求個小星星,感謝Star。

相關文章
相關標籤/搜索