Java數據結構和算法(七)B+ 樹


Java數據結構和算法(七)B+ 樹

數據結構與算法目錄(https://www.cnblogs.com/binarylei/p/10115867.html)

我們都知道二叉查找樹的查找的時間復雜度是 O(logN),其查找效率已經足夠高了,那為什么還有 B 樹和 B+ 樹的出現呢?難道它兩的時間復雜度比二叉查找樹還小嗎?答案當然不是, B 樹和 B+ 樹的出現是因為另外一個問題,那就是磁盤 IO。

一、計算機中數據的存儲原理

頁是計算機管理存儲的邏輯塊,硬件及操作系統往往將主存和磁盤存儲區分割為連續的大小相等的塊。每個塊都稱為一頁(在許多操作系統中,頁大小通常為 4K),主存和磁盤以頁為單位交換數據。

文件系統及數據庫系統的設計利用了磁盤預讀原理,將一個節點的大小設計為一個頁,這樣每個節點只需要一次 IO 就可以完全載入。

眾所周知,IO 操作的效率很低,那么,當在大量數據存儲中,查詢時我們不能一下子將所有數據加載到內存中,只能逐一加載磁盤頁,每個磁盤頁對應樹的節點。造成大量磁盤 IO 操作(最壞情況下為樹的高度)。平衡二叉樹由於樹深度過大而造成磁盤 IO 讀寫過於頻繁,進而導致效率低下。

所以,我們為了減少磁盤 IO 的次數,就你必須降低樹的深度,將“瘦高”的樹變得“矮胖”。一個基本的想法就是:

  • 每個節點存儲多個元素
  • 摒棄二叉樹結構,采用多叉樹

這樣就引出來了一個新的查找樹結構 - 多路查找樹。 根據 AVL 給我們的啟發,一顆平衡多路查找樹(B~樹)自然可以使得數據的查找效率保證在 O(logN) 這樣的對數級別上。

二叉樹與 B 樹

下面來具體介紹一下 B 樹(Balance Tree),

二、B 樹

一個 m 階的 B 樹具有如下幾個特征:B 樹中所有結點的孩子結點最大值稱為 B 樹的階,通常用 m 表示。一個結點有 k 個孩子時,必有 k-1 個關鍵字才能將子樹中所有關鍵字划分為 k 個子集。

2.1 特點

  1. 根結點至少有兩個子女。
  2. 每個中間節點都包含 k-1個 元素和 k 個孩子,其中 ceil(m/2) ≤ k ≤ m
  3. 每一個葉子節點都包含 k-1 個元素,其中 ceil(m/2) ≤ k ≤ m
  4. 所有的葉子結點都位於同一層。
  5. 每個節點中的元素從小到大排列,節點當中k-1個元素正好是k個孩子包含的元素的值域划分
  6. 每個結點的結構為:(n,A0,K1,A1,K2,A2,… ,Kn,An)
    其中,Ki(1≤i≤n) 為關鍵字,且 Ki < Ki + 1 (1 ≤ i ≤n-1)。
    Ai(0 ≤ i ≤ n)為指向子樹根結點的指針。且 Ai 所指子樹所有結點中的關鍵字均小於 Ki + 1。
    n 為結點中關鍵字的個數,滿足 ceil(m / 2) - 1≤ n ≤m - 1。

示例:三階 B 樹

三階 B 樹

2.1 查詢

以上圖為例:若查詢的數值為5:

第一次磁盤IO:在內存中定位(與17、35比較),比17小,左子樹;
第二次磁盤IO:在內存中定位(與8、12比較),比8小,左子樹;
第三次磁盤IO:在內存中定位(與3、5比較),找到5,終止。

整個過程中,我們可以看出:比較的次數並不比二叉查找樹少,尤其適當某一節點中的數據很多時,但是磁盤 IO 的次數卻是大大減少。比較是在內存中進行的,相比於磁盤 IO 的速度,比較的耗時幾乎可以忽略。所以當樹的高度足夠低的話,就可以極大的提高效率。相比之下,節點中的元素多點也沒關系,僅僅是多了幾次內存交互而已,只要不超過磁盤頁的大小即可。

注意:

  1. B 樹主要用於文件系統以及部分數據庫索引,如 MongoDB。而大部分關系數據庫則使用 B+ 樹做索引,例如:mysql 數據庫;
  2. 從查找效率考慮一般要求 B 樹的階數 m >= 3;
  3. B 樹上算法的執行時間主要由讀、寫磁盤的次數來決定,故一次 I/O 操作應讀寫盡可能多的信息。因此 B- 樹的結點規模一般以一個磁盤頁為單位。一個結點包含的關鍵字及其孩子個數取決於磁盤頁的大小。

三、B+ 樹

B+ 樹是 B 樹的變種,有着比 B 樹更高的查詢效率。下面,我們就來看看 B+ 樹和 B 樹有什么不同

3.1 特點

  1. 有 k 個子樹的中間節點包含有 k 個元素(B 樹中是 k-1 個元素),每個元素不保存數據,只用來索引,所有數據
    都保存在葉子節點。

  2. 所有的葉子結點中包含了全部元素的信息,及指向含這些元素記錄的指針,且葉子結點本身依關鍵字的大小
    自小而大順序鏈接。

  3. 所有的中間節點元素都同時存在於子節點,在子節點元素中是最大(或最小)元素。

下面是一棵 3 階的 B+ 樹:

B+ 樹

B+ 樹通常有兩個指針,一個指向根結點,另一個指向關鍵字最小的葉子結點。因些,對於 B+ 樹進行查找兩種運算:一種是從最小關鍵字起順序查找,另一種是從根結點開始,進行隨機查找。

3.2 查找

B+ 樹的優勢在於查找效率上 ,下面我們做一具體說明:

首先,B+樹的查找和B樹一樣,類似於二叉查找樹。起始於根節點,自頂向下遍歷樹,選擇其分離值在要查找值的任意一邊的子指針。在節點內部典型的使用是二分查找來確定這個位置。

(1)不同的是,B+樹中間節點沒有衛星數據(索引元素所指向的數據記錄),只有索引,而B樹每個結點中的每個關鍵字都有衛星數據;這就意味着同樣的大小的磁盤頁可以容納更多節點元素,在相同的數據量下,B+樹更加“矮胖”,IO操作更少
B 樹 和 B+ 樹數據結構區別

(2)其次,因為數據結構的不同,導致查詢過程也不同;B 樹的查找只需找到匹配元素即可,最好情況下查找到根節點,最壞情況下查找到葉子結點,所說性能很不穩定,而 B+ 樹每次必須查找到葉子結點,性能穩定

(3)在范圍查詢方面,B+ 樹的優勢更加明顯

B樹的范圍查找需要不斷依賴中序遍歷。首先二分查找到范圍下限,在不斷通過中序遍歷,知道查找到范圍的上限即可。整個過程比較耗時。

而 B+ 樹的范圍查找則簡單了許多。首先通過二分查找,找到范圍下限,然后同過葉子結點的鏈表順序遍歷,直至找到上限即可,整個過程簡單許多,效率也比較高。

例如:同樣查找范圍 [3-11],兩者的查詢過程如下:

B 樹 和 B+ 樹查找過程

四、總結

B+ 樹相比 B 樹的優勢:

  1. 單一節點存儲更多的元素,使得查詢的 IO 次數更少;
  2. 所有查詢都要查找到葉子節點,查詢性能穩定;
  3. 所有葉子節點形成有序鏈表,便於范圍查詢。

參考:

  1. 《簡單剖析B樹(B-Tree)與B+樹》:https://blog.csdn.net/z_ryan/article/details/79685072

每天用心記錄一點點。內容也許不重要,但習慣很重要!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM