1. 程式人生 > >B數,B+樹

B數,B+樹

int 不能 一個 數據 內存 過大 深度 平衡 OS

0 為什麽會有多叉樹

當在程序中存儲數據的時候,可以使用二叉搜索樹。

當輸入的過於均勻的時候可能生成深度過大的二叉搜索樹,最壞的情況是,輸入節點的key按照大小排序,此時生成的二叉搜索樹就是一個鏈表了。

因此,為了避免這種情況的出現,可以使用平衡二叉樹,例如AVL和紅黑樹。

但二叉搜索樹只是適用於數據存儲在內存中的情況。

當數據量過大,不能完全的在內存中存儲時,就需要將數據存儲到磁盤上。

為了檢索方便,仍然使用樹的結構。

如果存放在磁盤中的數據,仍然采用二叉搜索樹的形式,當磁盤中讀取出一塊數據,根據key的值,判斷目標應該在左子樹中,然後磁盤再去讀取左子樹數據所在磁盤位置的數據。然後叠代這個過程,直到找到了目標數據。

但是,磁盤每次讀取數據都需要一定的時間。因此樹高越大,那麽平均讀取依次數據需要讀取的磁盤次數也就越多。

cpu的計算速度遠快與磁盤讀取的次數,因此應該減少樹高,降低磁盤的讀取次數。

所以在每個節點中除了本節點key對應的值,再存儲多個子樹。而不是像二叉搜索樹,只存放左右子節點。

此時該結構就是B樹

2 B樹

2.1 結構

B樹的每個節點存放:

  1. 一個數值n,表示該節點中存在的節點個數。
  2. n個節點本身,按照節點關鍵字非降序存放(也就是從小打到),這n個節點的關鍵字,分割了本節點的n個子樹中key的取值範圍。
  3. 一個布爾值,表示概述是否是一個葉節點
  4. n+1個指針指向每一個子樹,取值範圍被n個關鍵字分割

註意父節點的指針在子樹中的指向。

技術分享圖片

2.2 特點

B樹具有

  1. 每個葉節點的樹高相同
  2. 每個節點所包含關鍵字個數有上下界。稱為B樹的最小度數。用t表示,一個大節點中小節點的個數最少為t-1個,最多為2t-1,其子樹數量最多為2t個。因此當t=2時,為2-3-4樹。t越大,樹高越小
  3. B樹的根至少包含一個子樹,其他節點至少有t個子樹

2.3 搜索

B樹的根節點時鐘在主存中。

搜索過程:

Node *serch(Node *root,int k)
{
    int i=0;
    for(;i<=root.n,k>x.key[i],++i)
    {

    }
    if(k==x.key[i])
    {
        return x.child[i];
    }else if(x.leaf == true)
    {
        return nullptr;
    }else{
        return serch(read(x.key),k);
    }
}

  

2.4 插入

B樹的插入,B樹的插入仍然和二叉樹的插入步驟類似,也就是說都要先判斷插入位置。

但是多了一個判斷:那麽就是一個節點中可存儲的節點個數,不能超過2t。當超過2t個的時候,需要這樣做。

  1. 遍歷找到要插入的位置。
  2. 判斷大節點中小節點的個數,如果為2t。那麽用本大節點中的中間節點將小結一分為二,將第n/2+1個節點上升到父節點。
  3. 如果父節點中小節點的個數也為2t了,那麽父節點重復上述分裂過程

技術分享圖片

2.5 刪除

刪除節點過程:

  1. 每次刪除一個節點的時候,都需要判斷該節點的父節點,叔叔節點,祖父節點中的子節點個數。如果刪除目標節點以後,父節點,叔叔節點,祖父節點的小節點個數滿足<=2t那麽合並這三個節點為一個節點
  2. 具體的刪除每個節點的策略:
    1. 當目標小節點是位於所有小節點中間的時候,那麽就合並該小節點兩邊指向的兩個子節點。
    2. 當目標小節點是所有小節點之後的節點的時候,那麽就從該節點指出的兩個子樹的節點中選出一個大於t的節點,然後將其換到目標節點處。如果都不夠,那麽先合並兩個子節點,然後提出中間節點。

下面是三種刪除的情況,只有兩層,沒有三層。

技術分享圖片

3 B+樹

B數,B+樹