從hash到二叉樹到紅黑樹到B樹到B+樹

要搞清這個幾個數據結構的問題,需要搞清楚他們的原理,並且有什麼問題,然後每一個新的結構能解決什麼問題。爲什麼會出現?爲什麼就用他了。

hash表:

首先hash表查序你很快,通過hash函數可以在O(1)的時間就能找到key值,且都是在內存中操作。hash表的內部實現可以已有兩種方式解決hash衝突問題。一個是順序找新地方放,一個是通過鏈表的方式記錄衝突的key值。順序防止有佔用bucket空間的問題和bucket key清楚後的特殊標記問題。同時還帶有空間擴容問題。所以一般採用鏈表的方式解決衝突,但是鏈表的方式也存在問題,雖然插入刪除很快,但是查詢時候需要遍歷鏈表,性能上是問題。

二叉搜索樹:

所以再次基礎上通過二叉搜索樹(中序遍歷有序)的方式替換鏈表。相當於查找的話是二分查找(時間複雜度O(logn))。但是二叉搜索樹有一個問題,就是這棵樹在某些極端場景下會是一顆鏈表,這樣的話就和鏈表的方式一樣時間複雜度就成了O(n).顯然這對hash的效率影響很大,爲此爲了解決這個問題就需要一顆二叉搜索平衡樹,也就是不會變成一個鏈表,二叉樹的高度相差不超過1.此時就出現了紅黑樹。

紅黑樹:

紅黑樹是一顆二叉樹,且是平衡的,搜索樹。因此滿足快速查詢,插入,刪除的特點。先不要去關紅黑樹怎麼實現的,爲什麼一會是紅一會是黑,這個是算法就這樣規定了。記住就行,或者有時間可以在細研究原理。紅黑樹在刪除和插入時候需要調整樹的平衡狀態,因此會存在紅黑樹的旋轉,這樣的目的是調整樹爲平衡狀態。這樣紅黑樹作爲hash解決hash衝突的鏈表後,都能大大提升hash表的性能。但是總體來講hash表,因爲bucket需要提前預分配,數據都在內存中,即便使用紅黑樹,紅黑樹的節點都在內存中。這樣就閒置了hash後者紅黑樹不可能處理大量的數據,因此內存畢竟有限。那麼在處理大量數據比如mysql, 存儲引擎處理的數據量(TB/PB)級別時候使用hash 紅黑樹就出現了很大的問題。那怎麼解決呢?還有一個問題就是紅黑樹,hash表只能查詢單個key比較搞笑,但是如果要查詢一個範圍的數據在只能一個一個的遍歷,性能也不高。在一個是紅黑樹因爲是二叉樹,大數據量層次會很高,如果不是全部放內存的話,則需要去盤上讀,這樣讀盤額次數就會變多。所以。。就出現了下面的數據結構。

B樹:

B樹是一個多叉樹,意思就是一個節點可以有多個子節點(B樹中叫多少介多少介)。這樣有個好處就是這個樹不會太高,因此放盤的IO就會變少。整棵樹按照索引(就是表的key來組織,比如表示userid<->name,則按照userid作爲這個樹的索引構建這棵樹),此時當有索引插入B樹時候,B樹會根據當前節點保存的關鍵字的個數(就是能保存多少個userid<->name對)來添加進一個樹的節點頁面中。如果關鍵字的個數已經達到設置的最大值比如 4個,則新增加進來的的userid會導致這個節點分裂。分裂的意思就是按照(4+1)/2=2的方式,將前面2個分離成3號位的前面(左)子樹,後面兩個分裂成3號位userid的右子樹(後面子樹)。然後3好上升添加到父節點裏面去。這也就是說當往B樹中插入刪除時候會導致樹分裂合併等操作。這樣當去遍歷某個key的時候,則從root開始就知道往那邊走,區間在哪裏。然後一層一層的往下找,最終找到對應的節點,讀取裏面保存的userid的name值。但是B數據也存在一個問題就是範圍查找的問題,也需要不停的遍歷某個範圍的所有的節點才能找到,而是都需要從root開始。所以在範圍查找上性能也不好,爲此提出了B+樹。

B+樹

和B樹一樣,B+樹也存在樹的分裂和合並的操作,原理和B樹大概差不多。但是B+樹和B樹有亮點很不錯一樣的就是:B+樹非葉子節點不存儲數據,存儲的是索引也就是一堆userid,所以一個非葉子節點可以存儲很多usrid.這樣這棵樹可以做到很矮,很胖,這樣對磁盤的訪問次數再次降低。第二點是B+樹的葉子積極點之間都是通過雙向鏈表鏈接的。爲什麼要這樣,因爲這樣就是就便於範圍查找,比如需要查序userid<100的同學的名字,則只需要從root開始遍歷找到100 userid的葉子節點,然後從葉子節點讀取到數據,小於100的數據都在從這個節點開始向左直接就可以讀取到,不用在從root遍歷來,這樣就提高了性能。所以B+樹就誕生了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章