數據結構 - 樹 - B樹、B+樹

前言

動態查找樹主要有:二叉查找樹(Binary Search Tree),平衡二叉查找樹(Balanced Binary Search Tree),紅黑樹(Red-Black Tree ),B-tree/B+-tree/ B*-tree (B~Tree)。前三者是典型的二叉查找樹結構,其查找的時間複雜度O(log2N)與樹的深度相關,那麼降低樹的深度自然會提高查找效率。

但是咱們有面對這樣一個實際問題:就是大規模數據存儲中,實現索引查詢這樣一個實際背景下,樹節點存儲的元素數量是有限的(如果元素數量非常多的話,查找就退化成節點內部的線性查找了),這樣導致二叉查找樹結構由於樹的深度過大而造成磁盤I/O讀寫過於頻繁,進而導致查詢效率低下(爲什麼會出現這種情況,待會在外部存儲器-磁盤中有所解釋),那麼如何減少樹的深度(當然是不能減少查詢的數據量),一個基本的想法就是:採用多叉樹結構(由於樹節點元素數量是有限的,自然該節點的子樹數量也就是有限的)。

這樣我們就提出了一個新的查找樹結構——多路查找樹。根據平衡二叉樹的啓發,自然就想到平衡多路查找樹結構,即B樹結構。

B樹

什麼是B樹

B 樹是爲了磁盤或其它存儲設備而設計的一種多叉(下面你會看到,相對於二叉,B樹每個內結點有多個分支,即多叉)平衡查找樹。

用階定義的B樹

B 樹又叫平衡多路查找樹。一棵m階的B 樹 的特性如下:

如下圖所示,即是一棵B樹:

B樹的類型和節點定義

B樹的類型和節點定義如下圖所示:

B樹中文件查找的具體過程

舉慄,這裏用少量數據構造一棵3叉樹的形式,實際應用中的B樹結點中關鍵字很多的。下圖中比如根結點,其中17表示一個磁盤文件的文件名;小紅方塊表示這個17文件內容在硬盤中的存儲位置;p1表示指向17左子樹的指針。

其結構可以簡單定義爲:

typedef struct {

    /*文件數*/

    int  file_num;

    /*文件名(key)*/

    char * file_name[max_file_num];

    /*指向子節點的指針*/

     BTNode * BTptr[max_file_num+1];

     /*文件在硬盤中的存儲位置*/

     FILE_HARD_ADDR offset[max_file_num];

}BTNode;

假如每個盤塊可以正好存放一個B樹的結點(正好存放2個文件名)。那麼一個BTNODE結點就代表一個盤塊,而子樹指針就是存放另外一個盤塊的地址。

下面,咱們來模擬下查找文件29的過程:

  • 根據根結點指針找到文件目錄的根磁盤塊1,將其中的信息導入內存。【磁盤IO操作 1次】    
  • 此時內存中有兩個文件名17、35和三個存儲其他磁盤頁面地址的數據。根據算法我們發現:17<29<35,因此我們找到指針p2。
  • 根據p2指針,我們定位到磁盤塊3,並將其中的信息導入內存。【磁盤IO操作 2次】    
  • 此時內存中有兩個文件名26,30和三個存儲其他磁盤頁面地址的數據。根據算法我們發現:26<29<30,因此我們找到指針p2。
  • 根據p2指針,我們定位到磁盤塊8,並將其中的信息導入內存。【磁盤IO操作 3次】    
  • 此時內存中有兩個文件名28,29。根據算法我們查找到文件名29,並定位了該文件內存的磁盤地址。
     

分析上面的過程,發現需要3次磁盤IO操作和3次內存查找操作。關於內存中的文件名查找,由於是一個有序表結構,可以利用折半查找提高效率。至於IO操作是影響整個B樹查找效率的決定因素。

當然,如果我們使用平衡二叉樹的磁盤存儲結構來進行查找,磁盤4次,最多5次,而且文件越多,B樹比平衡二叉樹所用的磁盤IO操作次數將越少,效率也越高。


B樹的高度

使用算法導論中對B樹高度的定義:

B+ 樹

B+樹 是應文件系統所需而產生的一種B樹的變形樹。

一棵m階的B+樹和m階的B樹的異同點在於:

      1.有n棵子樹的結點中含有n-1 個關鍵字; (此處頗有爭議,B+樹到底是與B 樹n棵子樹有n-1個關鍵字 保持一致,還是不一致)

      2.所有的葉子結點中包含了全部關鍵字的信息,及指向含有這些關鍵字記錄的指針,且葉子結點本身依關鍵字的大小自小而大的順序鏈接。 (而B 樹的葉子節點並沒有包括全部需要查找的信息)

      3.所有的非終端結點可以看成是索引部分,結點中僅含有其子樹根結點中最大(或最小)關鍵字。 (而B 樹的非終節點也包含需要查找的有效信息)

爲什麼說B+樹比B樹更適合實際應用中操作系統的文件索引和數據庫索引?

1、B+樹的磁盤讀寫代價更低

B+樹的內部結點並沒有指向關鍵字具體信息的指針。因此其內部結點相對B 樹更小。如果把所有同一內部結點的關鍵字存放在同一盤塊中,那麼盤塊所能容納的關鍵字數量也越多。一次性讀入內存中的需要查找的關鍵字也就越多。相對來說IO讀寫次數也就降低了。

2、B+樹的查詢效率更加穩定

由於非終結點並不是最終指向文件內容的結點,而只是葉子結點中關鍵字的索引。所以任何關鍵字的查找必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每一個數據的查詢效率相當。

參考

從B樹、B+樹、B*樹談到R 樹(July);

 

 

 

 

 

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