「觀感度:🌟🌟🌟🌟🌟」前端
「口味:螞蟻上樹」node
「烹飪時間:10min」git
本文已收錄在
Github
github.com/Geekhyt,感謝Star。github
周樹人先生曾經說過:學好樹,數據結構與算法你就掌握了一半!web
食堂老闆(童歐巴):就算咱們做爲互聯網浪潮中的葉子結點,也須要有不自量力的精神,就算不自量力是自不量力。由於就算終其一輩子只是個普通人,但你總不能爲了成爲一個普通人而終其一輩子吧。算法
今日菜譜,螞蟻上樹,下面介紹一下演員。數據庫
A 是 根節點
。C、D、F、G 是 葉子節點
。A 是 B 和 E 的 父節點
。B 和 E 是 A 的 子節點
。B、E 之間是 兄弟節點
。高度、深度、層
如上圖所示。爲了方便理解記憶,高度
就是擡頭看,深度
就是低頭看。與 高度、深度 不一樣,層
類比盜夢空間裏的樓,樓都是從 1 層開始計算,盜夢空間中的樓顛倒過來,從上往下。數組
每一個節點最多有兩個子節點,也就是 左子節點
和 右子節點
。數據結構
葉子節點全都在最底層,除了葉子節點以外,每一個節點都有左右兩個子節點。上文中的圖就是滿二叉樹。編輯器
葉子節點都在最底下兩層,最後一層的葉子節點都靠左排列,而且除了最後一層,其餘層的節點個數都要達到最大。
堆其實就是一種徹底二叉樹,通常採用的存儲方式是數組。
採用數組存儲徹底二叉樹,無須像鏈式存儲同樣額外存儲左右子節點的指針,能夠節省內存。
(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)
,分別對應二叉樹退化成鏈表的狀況和徹底二叉樹的狀況。
極端狀況下複雜度退化並非咱們想要的,因此咱們須要設計一種平衡二叉查找樹。平衡二叉查找樹的高度接近 logn
,因此查找、插入、刪除操做的時間複雜度也比較穩定,是 O(logn)
。
AVL 樹
是最早被髮明的平衡二叉查找樹(以發明者的名字來進行的命名),它定義任何節點的左右子樹高度相差不超過 1,而且左右兩個子樹都是一棵平衡二叉樹。
AVL 樹
是一種高度平衡的二叉查找樹。雖然查找效率高,可是爲了維持高度平衡,插入、刪除操做時都須要進行調整(左旋,右旋),須要付出很大的維持成本。
紅黑樹能夠被稱爲「網紅樹」了,它的出場率相比其餘的樹要高出一個天際線。與 AVL 樹不一樣,紅黑樹只是作到了近似平衡,並非嚴格意義上的平衡。因此在維護平衡付出的成本上比 AVL 樹要低,查找、插入、刪除等操做的性能都比較穩定,時間複雜度都是 O(logn)
。
一棵合格的紅黑樹應該知足:
紅黑樹在工程上有着大量的應用,由於工程上對性能的穩定性要求是很高的。正由於紅黑樹的性能比較穩定,它扛起了工程應用上的大旗。
Google、百度一類的搜索引擎強大的關鍵詞提示功能的背後,最基本的原理就 Trie 樹
,經過空間換時間,利用字符串的公共前綴,下降查詢的時間以提升效率。除此以外,還有不少應用,好比:IP 路由中使用了 Trie 樹的最長前綴匹配算法,利用轉發表選擇路徑以及 IDE 中的智能提示等。
Trie 樹
是一棵非典型的多叉樹模型,它和通常的多叉樹不一樣,咱們能夠對比一下它們結點的數據結構設計。通常的多叉樹結點中包含結點值和指向子結點的指針。而 Trie 樹的結點中包含的是該結點是不是一個串的結束,以及字母映射表。經過字母映射表咱們能夠經過一個父結點來獲取它全部子結點的值。
在 Trie 樹 中查找字符串的時間複雜度是 O(k)
,k 是要查找的字符串長度。
上圖中的 Trie 樹由 5 個單詞構成,分別是 color、coat、city、hi、hot
。根結點的值爲空。
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); } } 複製代碼
咱們知道,將索引存儲在內容中,查詢速度是比存儲在磁盤中快的。可是當數據量很大的狀況下,索引也隨之變大。內存是有限的,咱們不得不將索引存儲在磁盤中。那麼,如何提高從磁盤中讀取的效率就成了工程上的關鍵之一。
大部分關係型數據庫的索引,好比 MySQL、Oracle,都是用 B+ 樹來實現的。
B+ 樹比起紅黑樹更適合構建存儲在磁盤中的索引。B+ 樹是一個多叉樹,在相同個數的數據構建索引時,其高度要低於紅黑樹。當藉助索引查詢數據的時,讀取 B+ 樹索引,須要更少的磁盤 IO 次數。
一個 m 階的 B 樹知足以下特徵:
1.看到這裏了就點個贊支持下吧,你的「贊」是我創做的動力。
2.關注公衆號前端食堂,「你的前端食堂,記得按時吃飯」!
3.本文已收錄在前端食堂Github
github.com/Geekhyt,求個小星星,感謝Star。