前言需求算法
咱們上一篇文章中介紹了平衡二叉樹,以及爲何會有平衡二叉樹?sql
但其實二叉樹的操做效率較高,其實也是存在一些問題的數據庫
咱們通常二叉樹加載存放到內存中構建成,假如節點比較多(億:單位)性能
1.構建二叉樹時,須要屢次進行I/O 操做
(海量數據存在數據庫/文件
中),速度有影響
2.節點海量,會形成二叉樹高度很大,下降操做速度學習
這時咱們就提出一種樹想解決這個問題:多叉樹
優化
1.在二叉樹中
,每一個節點有數據項,最多有兩個子節點
。若是容許每一個節點有更多數據項和更多的子節點
,就是多叉樹(multiway Tree)
spa
2.多叉樹經過從新組織節點,減小樹的高度
,對二叉樹進行優化設計
(示例圖:2-3樹、2-3-4樹就是多叉樹)3d
2-3樹便是最簡單的B樹結構,具備如下特色:指針
一、全部葉子節點都在同一層(B樹都知足這個條件)
二、有一個元素項且有兩個子節點叫二節點、二節點要麼有兩個子節點、要麼就沒子節點
三、有二個元素項且有三個子節點叫三節點、三節點要麼有三個子節點、要麼就沒子節點
四、由二節點與三節點構成的成爲2-3樹
咱們發現三節點EJ、有AC、H、L 子節點
其中它們的關係是 AC < H < L,而AC的關係又是 A < C的
將數列{16, 24, 12, 32, 14, 26, 34, 10, 8, 28, 38, 20}
構建成2-3樹, 並保證數據插入的大小順序。
第一步:插入:16 放入後成爲二節點(二節點有一個元素項,兩個子節點)
第二步:插入:24 放入後成爲三節點(三節點有二個元素項,三個子節點)
第三步:插入:12 時按理說應該是插入16前面,可是插入16前行麼?
不行,由於放入後就不是三節點了,變成了三個元素項了,咱們須要拆
第四步:插入:32 比16節點還要大,因此咱們從右子節點開始找位置
從右子節點找位置,嘗試的從24 節點後邊去放,判斷是否知足三節點
第五步:插入:14 同理,比16節點小,因此從左子節點開始找位置
從左子節點找位置,嘗試的從12 節點後邊去放,判斷是否知足三節點
第六步:插入:26 比16節點還要大,因此咱們從右子節點開始找位置
按理說咱們應該是放入2四、32 中間的,可是能放嗎?
不行,放了就變成三個元素項了,而且也不能成爲2四、32的子節點,由於放了三節點就只有一個子節點了,也不符合要求(三節點要麼有三個子節點、要麼就沒子節點)
所以咱們只能往上拆,使插入26 節點也知足條件要求
第七步:插入:34 比26 大,因此咱們從右子節點開始找位置
從右子節點找位置,嘗試的從32 節點後邊去放,判斷是否知足三節點
第八步:插入:10 比16節點小,因此從左子節點開始找位置
按理說咱們應該是放入12 前邊的,可是能放嗎?
不行,放了就變成三個元素項了,而且也不能成爲十二、14的子節點,由於放了三節點就只有一個子節點了,也不符合要求(三節點要麼有三個子節點、要麼就沒子節點)
那麼按照以前的插入節點26的思路,咱們須要拆節點不是嘛?
可是此時並不知足B樹的特色:全部葉子節點都在同一層
,因此咱們須要調整
第九步:插入:8 比16節點還要小,因此咱們從左子節點開始找位置
按理說咱們應該是放入12 前邊的,可是12 有子節點,再進行尋找
從左子節點找位置,嘗試的從10 節點前邊去放,判斷是否知足三節點
第十步:插入:28 比16節點大,因此咱們從右子節點開始找位置
按理說咱們應該是放入26 後邊的,可是26有子節點,再進行判斷尋找
按理說咱們應該是放入32 前邊的,可是能放嗎?
不行,放了就變成三個元素項了,而且也不能成爲3二、34的子節點,由於放了三節點就只有一個子節點了,也不符合要求(三節點要麼有三個子節點、要麼就沒子節點)
那麼按照以前的插入節點的思路,咱們須要拆節點不是嘛?
第十一步:插入:38 比16節點大,因此咱們從右子節點開始找位置
按理說咱們應該是放入2六、32 後邊的,可是放入後就變成三個元素項了,不過2六、32有子節點,再進行判斷尋找。
從右子節點找位置,嘗試的從34節點後邊去放,判斷是否知足三節點
第十二步:插入:20 比16節點大,因此咱們從右子節點開始找位置
按理說咱們應該是放入26,32 前邊的,可是放入後就變成三個元素項了,不過2六、32有子節點,再進行判斷尋找。
從左子節點找位置,嘗試的從20節點前邊去放,判斷是否知足三節點
咱們能夠看看B樹的這些節點圖來多多認識經過從新組織節點,減小樹的高度
1.如圖B樹經過經過從新組織節點,減小樹的高度
2.文件系統及數據庫的設計者利用磁盤預讀原理,將一個節點的大小設爲等於一個頁的大小(一般爲4k)
,這樣每一個節點只須要一次I/O 便可
3.將樹的度M設置爲1024,在600億個元素中最多隻須要4次I/O便可讀取想要的元素
,普遍用於文件存儲系統以及數據庫系統中
(會不會有小夥伴提問:什麼是樹的度M?)
講樹的度M以前須要知道什麼是節點的度?
通常來講咱們都知道二叉樹最多有兩個子節點
假如A節點有B、C 兩子節點,咱們稱A節點的度爲2,即度爲子樹有幾個。
那麼樹的度呢?指全部節點的度裏的最大的值,即爲樹的度M
咱們前面介紹的2-3樹、甚至2-3-4樹,它們也是屬於B樹,我能夠先看看以前咱們學習Mysql時,常常聽見某種類型的索引是基於B樹或者B+樹的原理是個什麼狀況呢?
咱們先說明B樹的幾個點:
第一點:B樹有一個概念叫:階,指的是節點的最多子節點個數,好比2-3樹階是3,2-3-4樹的階是4
第二點:B樹的搜索:從根節點開始,對節點內的關鍵字(有序)序列進行二分查找,若是命中則結束,不然進入查詢關鍵字所屬範圍的兒子節點,重複操做,直到所對應的兒子節點爲指針爲空或者已經是葉子節點
第三點:關鍵字集合分佈在整顆樹中,即葉子節點和非葉子節點都存放數據
第四點:搜索有可能在非葉子節點就結束
第五點:其搜索性能等價於在關鍵字全集內作一次二分查找
B+樹是B樹的變體,也是一種多路搜索樹
咱們說明B+樹與B樹的一些特色
第一點:B+樹的搜索與B樹也基本相同,區別是B+樹只有達到葉子節點纔會命中(B樹能夠在非葉子節點命中)
,性能也等價於作一次二分查找
第二點:全部關鍵字都出如今葉子節點的鏈表中(數據只能在葉子節點),這叫稠密索引且鏈表中的關鍵字剛好是有序的
第三點:非葉子節點至關因而葉子節點的索引(稀疏索引),葉子節點是存儲數據的數據層
第四點:不可能在非葉子節點命中
可能小夥伴會很奇怪,不是一上來就找到節點五?
一上來找到的實際上是索引,數據它在葉子節點上
咱們能夠看看使用場景來體驗一下B+樹的結構
咱們不想一個一個的檢索,那麼有沒有辦法把這些數據分割成幾部分?
咱們使用什麼算法來體現出這種分割的思想呢?
假如咱們這時使用B+樹的結構尋找28,咱們上來無需從一個節點一個節點開始,只須要找到範圍的索引,一下就過濾了3/2的不符合範圍的數據,某種意義來講比二分還狠
B* 樹是B+樹的變體,在B+樹的非根和非葉子節點上添加指向兄弟指針的操做
可是B* 樹也有它的規定說明:
第一點:B 樹定義了非葉子節點關鍵字個數至少爲(2/3) M,即塊最低使用率爲2/3,而B+樹的最低使用率爲B+樹的1/2
第二點:從第一點能夠看出,B*樹分配新節點的機率比B+樹要低,空間使用率更高