參考:https://www.cnblogs.com/caoshouling/p/13574423.html
理解:二叉樹的查找的優化,也是利用了類似二分查找的思想,讓查找的時間復雜度變成O(log2 n)
1. 樹
N叉樹浪費鏈接的存儲空間,N越大浪費越嚴重
解決:N等於2時鏈接空間浪費率最低,於是有了二叉樹
2. 二叉樹
優點:鏈接空間浪費率達到最低。
缺點:無約束的二叉樹是無序的,查找的時間復雜度為O(N),
解決:有了二叉搜索樹BST(Binary Search Tree)(又稱排序二叉樹、有序二叉樹、二叉查找樹)
3. 二叉搜索樹BST
優點:排序二叉樹查詢、刪除和插入的平均時間復雜度都是O(log2 n)
缺點:但是隨着節點的添加和刪除,查詢的時間復雜度在O(log2 n) 到O(n)之間,
也就是說極端情況可能成為鏈表結構,查詢時間復雜度變成O(n)
解決:在添加和刪除節點時要維持二叉樹的平衡 -> 平衡二叉樹(AVL樹)、紅黑樹等
場景:實際使用不多
4. 平衡二叉樹(AVL樹)
優點:AVL樹是高度平衡的二叉樹,查找效率非常高,接近二分查找。
缺點:每次插入和刪除都需要維護平衡,代價高,耗時大。
解決:不維持嚴格平衡,只保證近似平衡 -> 紅黑樹
場景:實際使用不多
5. 近似平衡的二叉樹-紅黑樹
優點:性能穩定,插入、刪除、查找的復雜度在最好、最壞的情況都是O(log2 n) ,性能略微遜色AVL樹。
實際中使用的比較多的。
缺點:比較適合數據全部加載到內存中。但是數據量大到大量數據在磁盤,需要多次加載到磁盤中,每個節點的訪問都要經過一次磁盤I/O, 效率是非常低下的。
解決:為了減少減少磁盤IO,減少樹的高度,使樹變得“矮胖”(多叉樹)-> B樹和B+樹
數據庫索引多使用 B樹和B+樹
應用場景:使用比較多
JAVA8 HashMap的底層實現,數組+ 鏈表/紅黑樹
其中元素個數小於8時是鏈表,元素個數大於8時是紅黑樹;如果已經是紅黑樹,元素個數減為6(不是8的原因:避免頻繁轉換)時退化為鏈表。
6. B樹(又稱B-tree樹或B-樹)
優點:減少I/O次數,多路查找樹,B樹在提高了磁盤IO性能
B-樹查詢時間復雜度不固定,與 key 在樹中的位置有關,最好為O(1)
缺點:沒有解決元素遍歷的效率低下的問題,不利於遍歷和范圍查找。
解決:所有數據放在葉子節點節點上,組成一個雙向鏈表,非葉子節點存儲主鍵索引 -> B+樹
場景:MongoDB默認存儲引擎使用了B樹。
說明:讀多寫少且對遍歷數據的需求不強,B 樹與 LSM 樹在該場景下相比B+樹有更大的優勢
7. B+樹:B樹的改進版
優點:只有葉節點會存儲數據
場景:MySQL的InnoDB存儲引擎使用了B+樹
注意:B樹和B+樹的查詢效率肯定不如紅黑樹,但是紅黑樹內存中才有優勢。
8. B*樹:B+樹的改進版
9. 跳表:
鏈表加多級索引的結構
可以看成是鏈表實現二分查找,基於范圍查詢比紅黑樹效率高。
理論上經過改造后可以代替B+樹成為數據庫存儲索引設計。
10. LSM樹
無論是 B 樹還是 B+ 樹,向這些數據結構組成的索引文件中寫入記錄都需要執行的磁盤隨機寫。
LSM 樹的優化邏輯就是犧牲部分的讀性能,將隨機寫轉換成順序寫以優化數據的寫入。
a.在不限制寫入的情況下;
LSM 樹的寫入性能是 B 樹的 1.5 ~ 2 倍;
LSM 樹的讀取性能是 B 樹的 1/6 ~ 1/3;
b.在限制寫入的情況下;
LSM 樹的寫入性能與 B 樹的性能基本持平;
LSM 樹的讀取性能是 B 樹的 1/4 ~ 1/2;
場景:MongoDB默認存儲引擎使用了B樹,備用引擎是LSM樹。
Hbase中存儲設計使用了LSM樹。
問題1:Redis為什么采用跳表而不是紅黑樹?
(1)插入、刪除、查找以及迭代輸出有序序列這幾個操作,紅黑樹也可以完成,時間復雜度跟跳表是一樣的。但是,按照區間來查找數據這個操作,紅黑樹的效率沒有跳表高。
(2)跳表插入和刪除更快、操作更簡單。平衡樹的插入和刪除操作可能引發子樹的旋轉調轉,邏輯復雜。
(3)算法實現簡單
(4)跳表更加靈活,他可以通過改變索引構建策略,有效平衡執行效率和內存消耗。
問題2:為什么MongoDB使用B樹,而mysql使用B+樹?
(1)B+樹內節點不存儲數據,所有 data 存儲在葉節點導致查詢時間復雜度固定為 log n。
B-樹查詢時間復雜度不固定,與 key 在樹中的位置有關,最好為O(1)
MongoDB追求單條記錄的效率發揮到極致,而不重視范圍查找(雖然也支持,但是性能不如B+樹)。
(2)B+樹擅長范圍查找,而B樹不擅長。(最重要的原因)
B+樹查詢時間復雜度固定為logn,性能穩定。
MySQL追求穩定和范圍查詢。
(3)B+樹中非葉子節點不存儲關鍵字,利於加載到內存。
問題3:B+樹、B樹對比?
(1)B+樹的所有數據都在葉子節點中,非葉子節點不存儲數據,只是索引。
B樹中的節點存儲數據;
(2)B+樹葉子節點之間是雙向鏈表。
B 樹中的葉子節點並不需要鏈表來串聯。
(3)B+樹更加適合范圍查詢、且查詢性能更穩定