B Tree 系列
摘錄:
https://blog.csdn.net/v_JULY_v/article/details/6530142
動態查找樹有: 二叉查找樹,自平衡的二叉查找樹系列(如avl,紅黑樹,左傾紅黑樹),2-3樹,2-3-4樹,B樹系列。樹的高度和查找效率高度相關。
但在大規模數據儲存中,二叉查找樹等必然高度增加,造成磁盤i/o讀寫過於頻繁,導致查詢效率下降。
因此采用多叉樹通過降低樹的高度提高效率。B樹系列就是通過保持較低的高度從而避免磁盤過於頻繁的查找存取操作。
wiki:https://en.wikipedia.org/wiki/B-tree
B樹
相比於內存, 訪問磁盤/磁帶等塊設備時, 大塊數據讀寫有更好的性能。
為高效使用這類設備, 盡量將多份數據放入一個盤塊block中,同一磁道中。就可以提高讀寫信息時的查找時間。
B樹是解決此問題的算法統稱。
應用:
B樹(或其變形)廣泛應用於有大量元數據需要保存到外部存儲介質的應用場景, 例如文件系統, 數據庫, 以及存儲自精簡/壓縮/重刪等特性中.
B樹與紅黑樹有相似的地方:一棵含n個結點的B樹的高度也為O(lgn),但可能比一棵紅黑樹的高度小許多,應為它的分支因子比較大。
B樹與紅黑樹最大的不同在於,B樹的結點可以有許多子女,從幾個到幾千個。
所以,B樹可以在O(logn)時間內,實現各種如插入(insert),刪除(delete)等動態集合操作。
B樹中的每個結點根據實際情況可以包含大量的關鍵字信息和分支(當然是不能超過磁盤塊的大小,根據磁盤驅動(disk drives)的不同,一般塊的大小在1k~4k左右);
這樣樹的深度降低了,這就意味着查找一個元素只要很少結點從外存磁盤中讀入內存,很快訪問到要查找的數據。
wiki
B樹(英語:B-tree)是一種自平衡的樹,能夠保持數據有序。這種數據結構能夠讓查找數據、順序訪問、插入數據及刪除的動作,都在對數時間內完成。
B樹,多叉樹,平衡多路查找樹。一個節點可以擁有2個以上的子節點。B樹可以看作是2-3查找樹的一種擴展。當m等於3時,就是2-3樹。當m等於2時,就是2叉搜索樹。
定義
B樹的階(英語對應order)定義是不統一。wiki
1. 最開始定義是在一個非根節點中,key的最小值。對這個定義后人有異議。
2. Knuth (1998,)order為孩子們的最大數量(比key的最大值大1) defining the order to be maximum number of children (which is one more than the maximum number of keys).
所以按照Knuth定義一棵m階的B樹:(國內教材所用的定義)
- Every node has at most m children.
- 每個節點最多有m個孩子。
- Every non-leaf node (except root) has at least ⌈m/2⌉ child nodes.
- 非葉非根節點至少有[m/2]個兒子。[m/2]表示取大於m/2的最小整數。
- The root has at least two children if it is not a leaf node.
- 根節點至少有2個兒子。除非它本身是葉子節點,即整棵樹只有它一個節點。
- A non-leaf node with k children contains k − 1 keys.
- 非葉節點:有k個兒子,就有k-1個keys。
- All leaves appear in the same level and carry no information.
- 所有葉子節點在同一層,不攜帶信息data。
- ⚠️增加一條:非root節點的key的數量是[m/2]-1至m-1。
內部節點
通常代表一個orderd set of element(這里指的是key和它對應的data組成一個記錄/元素)和孩子節點的指針。
data表示key對應的條目在硬盤上的邏輯地址。
每個節點包含n個關鍵字信息:(n, p0, k1, k2,...Kn, Pn)
- Ki(i=1..n)是關鍵字,⚠️關鍵字對應一個data。
- Pi是指向子樹的指針,並且Pi-1所指向的兒子內的所有key都小於Ki,但大於K(i-1)
根節點
遵守內部節點擁有孩子的上線,最多有m個。無需遵守下限,因為當樹只有根節點時,它沒有孩子。
葉子節點
只儲存keys和指針,不攜帶信息:key對應的data是空的。
非葉結點是由葉結點分裂而來的,所以葉結點關鍵字個數也滿足[[m/2]-1,m-1];
B樹的插入
插入操作,是插入一條記錄,即key:value對兒。從葉子節點插入記錄,如果需要從下向上調整。
過程:
1. 插入記錄,根據key的值,找到對應的葉子節點。
2.判斷當前節點的key的數量是否<= M-1, true則完成插入,false則繼續第三步。
3.把當前節點以中間位置的key為中心,左右的key被“分裂”成兩個子節點,中間的key上傳到父親節點中。然后將父節點作為“當前節點”,繼續2,3步驟。最壞的情況是一直分裂到root節點,建立一個新的root,整個B樹增加一層。!
B樹的刪除
根據key刪除記錄。
刪除方法類似2-3樹。看是否是葉子節點。
參考:https://zhuanlan.zhihu.com/p/27700617
- 如果刪除的key位於非葉節點,則使用后繼key(即中序排列后的后繼記錄)覆蓋要刪除的key,然后在葉節點上刪除后繼key。
- 現在“當前節點”為刪除后繼key的節點。該節點要key的數量滿足[m/2]-1,true則結束刪除操作,false則繼續下一步。
- 從父兄那里借key來滿足B樹結構定義。判斷兄弟節點是否有富裕的key:
- true則通過兄弟節點上傳一個key,再從父親那下移一個key來完成B樹結構,刪除操作結束。
- false則看看父親那里是否有富裕的節點:
- true的話從父親那借用一個節點,然后再和一個兄弟合並,刪除操作結束。
- false的話,仍然從父親那借用節點並和一個兄弟合並。此時父親節點不滿足[m/2]-1的條件,因此以父節點為“當前節點”,向它的父兄借用節點。即再執行第三步。
舉例子:
這是一棵m=5的B樹,刪除C
通過上面的步驟可知:
1.找到c的后繼D, 然后上移D代替C(代碼是復制key,刪除原來的D)。
2.發現上移D導致節點不符合定義(最少元素要[m/2]-1), 通過判斷父兄都不富裕,所以只能下移D,然后A,B,D,E元素合並為一個節點。
3.此時父節點只有F元素了,所以繼續判斷,因為它的兄弟節點有富裕元素,所以可以借。把j下移到該節點,然后上移M給父節點。
結果:
B樹的特點:
B樹相對於平衡二叉樹的不同是,每個節點包含的關鍵字增多了,特別是在B樹應用到數據庫中的時候,數據庫充分利用了磁盤塊的原理(磁盤數據存儲是采用塊的形式存儲的,每個塊的大小為4K,每次IO進行數據讀取時,同一個磁盤塊的數據可以一次性讀取出來)把節點大小限制和充分使用在磁盤快大小范圍;把樹的節點關鍵字增多后樹的層級比原來的二叉樹少了,減少數據查找的次數和復雜度;
B+樹
B+樹是B樹的一個升級版,相對於B樹來說B+樹更充分的利用了節點的空間,讓查詢速度更加穩定,其速度完全接近於二分法查找。
傳統關系型數據庫,主要的索引結構就是B+樹。
B+樹把所有的數據都儲存在葉節點,內部節點只存放關鍵字和孩子指針。這個特點,讓遍歷不同於B樹。
B樹需要使用中序遍歷節點,而B+只需把所有的葉子節點串聯成鏈表即可。
- B+樹包括2種節點:內部節點(索引節點)和葉子節點。
- 根節點可以是索引節點或葉子節點。根節點的key個數最少可以只有1個
- B+樹的內部節點不保存數據,只用於索引,所有的數據/記錄保存在葉子節點內。
- m階B+樹:節點最多有m-1個關鍵字,這和B樹一樣。
- key按照從小到大的順序排列。
- 每個葉子節點都保存相鄰的葉子節點的pointer。因此方便范圍搜索,比B樹更快捷。
- ⚠️為了提高效率,規定非葉節點key的數量最低是[m-1]/2。
為什么B+樹比B 樹更適合實際應用中操作系統的文件索引和數據庫索引?
1. B+樹的磁盤讀寫代價更低。
因為內部節點沒有指向具體data的指針,因此相對B樹更小。如果把所有同一內部結點的關鍵字存放在同一盤塊中,那么盤塊所能容納的關鍵字數量也越多。一次性讀入內存中的需要查找的關鍵字也就越多。相對來說IO讀寫次數也就降低了。
2. B樹的查詢效率更穩定。
只有葉子結點內有具體data的指針,因此任何關鍵字的查找必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每一個數據的查詢效率相當。
3.最重要的是,B+樹誕生的目的是解決范圍查詢的效率問題,它的結構很好解決了這個問題。
B*-tree
B*-tree是B+-tree的變體,在B+樹的基礎上(所有的葉子結點中包含了全部關鍵字的信息,及指向含有這些關鍵字記錄的指針),B*樹中非根和非葉子結點再增加指向兄弟的指針;B*樹定義了非葉子結點關鍵字個數至少為(2/3)*M,即塊的最低使用率為2/3(代替B+樹的1/2)。
B+樹的分裂:當一個結點滿時,分配一個新的結點,並將原結點中1/2的數據復制到新結點,最后在父結點中增加新結點的指針;B+樹的分裂只影響原結點和父結點,而不會影響兄弟結點,所以它不需要指向兄弟的指針。
B*樹的分裂:當一個結點滿時,如果它的下一個兄弟結點未滿,那么將一部分數據移到兄弟結點中,再在原結點插入關鍵字,最后修改父結點中兄弟結點的關鍵字(因為兄弟結點的關鍵字范圍改變了);如果兄弟也滿了,則在原結點與兄弟結點之間增加新結點,並各復制1/3的數據到新結點,最后在父結點增加新結點的指針。
所以,B*樹分配新結點的概率比B+樹要低,空間使用率更高。
總結:
B樹:有序數組+平衡多叉樹;
B+樹:有序數組鏈表+平衡多叉樹;
B*樹:一棵豐滿的B+樹。
在大規模數據存儲的文件系統中,B~tree系列數據結構,起着很重要的作用,對於存儲不同的數據,節點相關的信息也是有所不同,
下面是畫的一個查找以職工號為關鍵字key,職工號為38的記錄的簡單示意圖。使用B+樹結構儲存數據。數據存放在磁盤內。
(這里假設每個物理塊容納3個索引,磁盤的I/O操作的基本單位是塊(block), 磁盤訪問很費時,采用B+樹有效的減少了訪問磁盤的次數。)
通過索引節點的搜索,最終在葉節點上找到對應key==38的記錄。
引用:
Bucket Li:"mysql 底層存儲是用B+樹實現的,知道原因么?內存中B+樹是沒有優勢的,但是一到磁盤,B+樹的威力就出來了"。