【轉載】B/B+樹、紅黑樹

背景:這幾天在看《高性能Mysql》,在看到創建高性能的索引,書上說mysql的存儲引擎InnoDB采用的索引類型是B+Tree,那么,大家有沒有產生這樣一個疑問,對于數據索引,為什么要使用B+Tree這種數據結構,和其它樹相比,它能體現的優點在哪里? 看完這篇文章你就會了解到這些數據結構的原理以及它們各自的應用場景.
二叉查找樹(BST)
簡介
二叉查找樹也稱為有序二叉查找樹,滿足二叉查找樹的一般性質,是指一棵空樹具有如下性質:
任意節點左子樹不為空,則左子樹的值均小于根節點的值.
任意節點右子BST不為空,則右子樹的值均大于于根節點的值.
任意節點的左右子樹也分別是二叉查找樹.
沒有鍵值相等的節點.
局限性及應用
一個二叉查找樹是由n個節點隨機構成,所以,對于某些情況,二叉查找樹會退化成一個有n個節點的線性鏈.如下圖:

BST

b圖為一個普通的二叉查找樹,大家看a圖,如果我們的根節點選擇是最小或者最大的數,那么二叉查找樹就完全退化成了線性結構,因此,在二叉查找樹的基礎上,又出現了AVL樹,紅黑樹,它們兩個都是基于二叉查找樹,只是在二叉查找樹的基礎上又對其做了限制.

AVL樹
簡介
AVL樹是帶有平衡條件的二叉查找樹,一般是用平衡因子差值判斷是否平衡并通過旋轉來實現平衡,左右子樹樹高不超過1,和紅黑樹相比,它是嚴格的平衡二叉樹,平衡條件必須滿足(所有節點的左右子樹高度差不超過1).不管我們是執行插入還是刪除操作,只要不滿足上面的條件,就要通過旋轉來保持平衡,而旋轉是非常耗時的,由此我們可以知道AVL樹適合用于插入刪除次數比較少,但查找多的情況。

AVL

從上面這張圖我們可以看出,任意節點的左右子樹的平衡因子差值都不會大于1.
局限性
由于維護這種高度平衡所付出的代價比從中獲得的效率收益還大,故而實際的應用不多,更多的地方是用追求局部而不是非常嚴格整體平衡的紅黑樹.當然,如果應用場景中對插入刪除不頻繁,只是對查找要求較高,那么AVL還是較優于紅黑樹.
應用
Windows NT內核中廣泛存在.

紅黑樹
簡介
一種二叉查找樹,但在每個節點增加一個存儲位表示節點的顏色,可以是red或black. 通過對任何一條從根到葉子的路徑上各個節點著色的方式的限制,紅黑樹確保沒有一條路徑會比其它路徑長出兩倍.它是一種弱平衡二叉樹(由于是若平衡,可以推出,相同的節點情況下,AVL樹的高度低于紅黑樹),相對于要求嚴格的AVL樹來說,它的旋轉次數變少,所以對于搜索,插入,刪除操作多的情況下,我們就用紅黑樹.
性質
每個節點非紅即黑.
根節點是黑的。
每個葉節點(葉節點即樹尾端NUL指針或NULL節點)都是黑的.
如果一個節點是紅的,那么它的兩兒子都是黑的.
對于任意節點而言,其到葉子點樹NIL指針的每條路徑都包含相同數目的黑節點.
查找、插入和刪除的時間復雜度都是O(logn)

紅黑樹

每條路徑都包含相同的黑節點.
應用
廣泛用于C++的STL中,map和set都是用紅黑樹實現的.
著名的linux進程調度Completely Fair Scheduler,用紅黑樹管理進程控制塊,進程的虛擬內存區域都存儲在一顆紅黑樹上,每個虛擬地址區域都對應紅黑樹的一個節點,左指針指向相鄰的地址虛擬存儲區域,右指針指向相鄰的高地址虛擬地址空間.
IO多路復用epoll的實現采用紅黑樹組織管理sockfd,以支持快速的增刪改查.
ngnix中,用紅黑樹管理timer,因為紅黑樹是有序的,可以很快的得到距離當前最小的定時器.
java中TreeMap的實現.

B/B+樹

注意B-樹就是B樹,-只是一個符號.

簡介

B/B+樹是為了磁盤或其它存儲設備而設計的一種平衡多路查找樹(相對于二叉,B樹每個內節點有多個分支),與紅黑樹相比,在相同的的節點的情況下,一顆B/B+樹的高度遠遠小于紅黑樹的高度(在下面B/B+樹的性能分析中會提到).B/B+樹上操作的時間通常由存取磁盤的時間和CPU計算時間這兩部分構成,而CPU的速度非常快,所以B樹的操作效率取決于訪問磁盤的次數,關鍵字總數相同的情況下B樹的高度越小,磁盤I/O所花的時間越少.
B樹中所有結點的孩子結點數的最大值稱為B樹的階,通常用m表示。
一棵m叉樹的性質如下:
樹中每個結點至多有m棵子樹(即至多含有m-1個關鍵字)
若根結點不是終端結點,則至少有兩棵子樹
除根結點以外的所有非葉子結點至少有[m/2](向上取整)棵子樹(即至少含有[m/2]-1個關鍵字)
所有非葉子結點的關鍵字:K[1], K[2], …, K[m-1];且K[i] < K[i+1];
非葉子結點的指針:P[1], P[2], …, P[m];其中P[1]指向關鍵字小于K[1]的子樹,P[m]指向關鍵字大于K[m-1]的子樹,其它P[i]指向關鍵字屬于(K[i-1], K[i])的子樹;
所有葉子結點位于同一層;

B樹

這里只是一個簡單的B樹,在實際中B樹節點中關鍵字很多的.上面的圖中比如35節點,35代表一個key(索引),而小黑塊代表的是這個key所指向的內容在內存中實際的存儲位置.是一個指針。
B+樹

B+樹是應文件系統所需而產生的一種B樹的變形樹(文件的目錄一級一級索引,只有最底層的葉子節點(文件)保存數據.),非葉子節點只保存索引,不保存實際的數據,數據都保存在葉子節點中.這不就是文件系統文件的查找嗎?我們就舉個文件查找的例子:有3個文件夾,a,b,c, a包含b,b包含c,一個文件yang.c, a,b,c就是索引(存儲在非葉子節點), a,b,c只是要找到的yang.c的key,而實際的數據yang.c存儲在葉子節點上.
所有的非葉子節點都可以看成索引部分

一棵m階的B+樹的性質(下面提到的都是和B樹不相同的性質)

每個分支結點最多有m棵子樹
非葉根結點至少有兩棵子樹,其他每個分支結點至少有[m/2](向上取整)棵子樹
結點的子樹個數與關鍵字個數相等
所有葉結點包含全部關鍵字及指向相應記錄的指針,而且葉結點中將關鍵字按大小順序排列,并且相鄰葉結點按大小順序相互鏈接起來
所有分支結點中僅包含它的各個子結點中關鍵字的最大值及指向子結點的指針
m階的B+樹與m階的B樹的主要差異在于:

在B+樹中,具有n個關鍵字的結點只含有n棵子樹,即每個關鍵字對應一棵子樹;而在B樹中,具有n個關鍵字的結點含有(n+1)棵子樹
在B+樹中,每個結點(非根結點)關鍵字個數n的范圍是[m/2] <=n<=m(根結點:1<=n<=m),在B樹中,每個結點(非根結點)關鍵字個數n的范圍是[m/2]-1<=n<=m-1(根結點:1<=n<=m-1)(都是向上取整)
在B+中,葉結點包含信息,所有非葉結點僅起到索引作用,非葉結點中的每個索引項只含有對應子樹的最大關鍵字和指向該子樹的指針,不含有該關鍵字對應記錄的存儲地址
在B+中,葉結點包含了全部關鍵字,即在非葉結點中出現的關鍵字也會出現在葉結點中;而在B樹中,葉結點包含的關鍵字和其他結點包含的關鍵字是不重復的。

B+樹

非葉子節點(比如5,28,65)只是一個key(索引),實際的數據存在葉子節點上(5,8,9)才是真正的數據或指向真實數據的指針.

應用

B和B+樹主要用在文件系統以及數據庫做索引.比如Mysql;

B/B+樹性能分析

n個節點的平衡二叉樹的高度為H(即logn),而n個節點的B/B+樹的高度為logt((n+1)/2)+1;   
若要作為內存中的查找表,B樹卻不一定比平衡二叉樹好,尤其當m較大時更是如此.因為查找操作CPU的時間在B-樹上是O(mlogtn)=O(lgn(m/lgt)),而m/lgt>1;所以m較大時O(mlogtn)比平衡二叉樹的操作時間大得多. 因此在內存中使用B樹必須取較小的m.(通常取最小值m=3,此時B-樹中每個內部結點可以有2或3個孩子,這種3階的B-樹稱為2-3樹)。
為什么說B+tree比B樹更適合實際應用中操作系統的文件索引和數據索引。

B±tree的內部節點并沒有指向關鍵字具體信息的指針,因此其內部節點相對B樹更小,如果把所有同一內部節點的關鍵字存放在同一盤塊中,那么盤塊所能容納的關鍵字數量也越多,一次性讀入內存的需要查找的關鍵字也就越多,相對IO讀寫次數就降低了.
由于非終結點并不是最終指向文件內容的結點,而只是葉子結點中關鍵字的索引。所以任何關鍵字的查找必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每一個數據的查詢效率相當。
ps:我在知乎上看到有人是這樣說的,我感覺說的也挺有道理的:
他們認為數據庫索引采用B+樹的主要原因是:B樹在提高了IO性能的同時并沒有解決元素遍歷的我效率低下的問題,正是為了解決這個問題,B+樹應用而生.B+樹只需要去遍歷葉子節點就可以實現整棵樹的遍歷.而且在數據庫中基于范圍的查詢是非常頻繁的,而B樹不支持這樣的操作(或者說效率太低)。

————————————————
版權聲明:本文為CSDN博主「N1314N」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/N1314N/java/article/details/89413308

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,892評論 2 372

推薦閱讀更多精彩內容