記事ディレクトリ
序文
B ツリーの基本ルール
-
各ノードには最大で m 個の子ノードがあります。m は正の整数です。ルート ノードを除いて、他のノードには少なくとも ⌈m/2⌉ の子ノードがあります。
-
各ノードのキー値は非降順に配置されます。ノード内のキー値 k について、n 個の子ノードがある場合、ノード内の n-1 個のキー値はノードを n 個の間隔に分割します。i 番目の間隔のキー値は k 未満であり、 i+1 番目の間隔のキー値は次のとおりです。キー値は k 以上です。
-
すべてのリーフ ノードは同じレイヤー上に位置し、キー値情報を含まず、外部に保存されたブロックとみなすことができます。
-
各非リーフ ノードのキー値の数は、子ノードの数から 1 減ります。
-
各ノードのキー値の数は次の条件を満たします:
⌈m/2⌉-1 <= キー値の数 <= m-1
B-treeのデータ挿入(文字説明+イラスト)
挿入ルールの概要:
1. ルート ノードから開始して、ノード内のキー値に従って比較し、適切なリーフ ノードを見つけます (比較結果は二分探索ツリーに似ています)。
2. キー値がすでにリーフ ノードに存在する場合は、対応する値を更新します。
3. リーフ ノードにキー値が存在しない場合は、キー値をリーフ ノードの適切な位置に挿入し、ノード内のキー値を順序どおりに保ちます。
4. キー値を挿入した後、リーフノード内のキー値の数が上限値 m-1 を超える場合、分割操作が実行されます。
将叶子节点的键值分成两部分,左边部分包含⌈(m-1)/2⌉个键值,右边部分包含⌊(m-1)/2⌋个键值。
将右边部分的键值和对应的子节点分离出来,形成一个新的叶子节点。
将新的叶子节点插入到叶子节点的右边,并更新父节点的键值信息。
5. キー値を挿入した後、リーフノード内のキー値の数が上限値 m-1 を超えない場合は、キー値を直接挿入します。
6. 親ノードが存在し、キー値挿入後に上限値 m-1 を超えた場合は、分割操作を実行します。
将父节点的键值分成两部分,左边部分包含⌈(m-1)/2⌉个键值,右边部分包含⌊(m-1)/2⌋个键值。
将右边部分的键值和对应的子节点分离出来,形成一个新的父节点。
将新的父节点插入到父节点的右边,并更新祖父节点的键值信息。
ルート ノードに到達するまで手順 6 を繰り返します。
(イラスト) 挿入状況は以下のカテゴリーに分類されます。
-
親ノードがないため、分割する必要はありません。
-
親ノードがあるため、分割する必要はありません。
-
親ノードを分割する必要はありません。
将叶子节点的键值分成两部分,左边部分包含⌈(m-1)/2⌉个键值,右边部分包含⌊(m- 1)/2⌋个键值。 将右边部分的键值和对应的子节点分离出来,形成一个新的叶子节点。
-
親ノードがあり、挿入されたノードを分割する必要があります。挿入後、親ノードを分割する必要はありません。葉ノード
のキー値は 2 つの部分に分割され、左側の部分には ⌈(m-1 )/2⌉ キー値、右側の部分には ⌊(m- 1)/2⌋ キー値が含まれます。
右側の部分のキー値を対応する子ノードから分離して、新しいリーフ ノードを形成します。リーフノードの右側に新規リーフノードを挿入し、親ノードのキー値情報を更新します。
-
親ノードがある場合は、挿入されたノードを分割する必要があり、挿入後に親ノードを分割する必要があります。
将父节点的键值分成两部分,左边部分包含⌈(m-1)/2⌉个键值,右边部分包含⌊(m-1)/2⌋个键值。
将右边部分的键值和对应的子节点分离出来,形成一个新的父节点。
将新的父节点插入到父节点的右边,并更新祖父节点的键值信息。
重复以上步骤,直到根节点
Bツリーデータ検索
データ配置の形式は二分木の検索に似ているため、検索も同様です。
B ツリー効率分析
メモリと外部メモリ間の検索時間の大きな違いを無視する場合:
仮定します:
有効な値の数 = N;
次数 = M;
次に: ノードの有効な値の数 = M/2 ~ M-1;
したがって: ツリーの高さは = log{M/2} N ~ log{M-1}N;
ノード内の検索の複雑さ = O(log{2}M/2) ~ O(log{2}M- 1);
したがって、最終時間計算量 = [ O(log{2}M/2 ) ~ O(log{2}M-1 ) ] * [ log{M/2} N ~ log{M-1}N ]
しかし、実際のアプリケーションではこの限りではなく、ノードへのアクセスは実際に外部メモリにアクセスするため、実際の時間は主に上位ノードから下位ノードにアクセスする処理で消費されます。
(理解のポイント) B ツリーの検索処理において、IO 操作はノードに入る操作であり、検索処理中にディスク上のノードにアクセスする必要がある場合、ディスクからノードを読み取るための IO 操作が必要になります。ディスクをメモリに取り込みます。
したがって、主な消費時間は、[ log{M/2} N ~ log{M-1}N ] 回の外部メモリへのアクセスです。!!!
N = 62*1000000000 ノードの場合、次数 M が 1024 の場合、log M / 2 N log_{M/2}Nログ_ _M / 2N <=
4、つまり 620 億個の要素のうち、このツリーの次数が 1024 の場合、ノードを見つけるのにかかる時間は 4 回未満で、二分探索を使用して要素をすばやく見つけ出すことで、読み取り数が大幅に削減されます。ディスクの。
Bツリーの役割
データベース インデックス: B ツリーはデータベースのインデックス構造としてよく使用され、データ検索と範囲クエリを効率的にサポートできます。
ファイル システム: ファイル システムのディレクトリ構造には B ツリーが使用され、ファイルの検索と管理を効率的にサポートできます。
キャッシュ システム: B ツリーを使用してシステム内のインデックス構造をキャッシュし、データ アクセスとクエリを高速化できます。
ルーティング テーブル: B ツリーを使用してルーティング テーブルを保存および検索し、ターゲット アドレスをすばやく見つけることができます。
B+ ツリーの基本ルール
- ブランチノードのサブツリーポインタはキーワードの数と同じです
- ブランチ ノードのサブツリー ポインタ p[i] は、[k[i]、k[i+1]] の間のキー値の範囲を指します)
- すべてのリーフ ノードは、リンク ポインターを追加することによって相互にリンクされます。
すべてのキーワードとそのマッピング データはリーフ ノードに表示されます (すべてのデータは最下層に保存されます)。 - すべてのキーワードはリーフ ノードのリンク リストに表示され、リンク リスト内のノードは順序付けされます。
- ブランチノード内のデータにヒットすることはできません(すべてのデータは最下層に格納されます)
- ブランチノードはリーフノードのインデックスに相当し、リーフノードはデータが格納されるデータ層です。
B+ツリーとBツリーの比較
結論から先に言いますと、
1. ランダム検索には B-tree が、範囲検索には B+ ツリーが適しています
2. B+ ツリーは比較的省スペースです 3.
データの挿入と削除の場合、B+ ツリーは理由
:
- B ツリーの各ノードには、データの保存とインデックスの構築に使用されるキーワードと対応するポインターが含まれています。B ツリーのノードはデータを直接格納できるため、検索時にデータが配置されているノードを直接見つけることができます。
B+ ツリーの各ノードにはキーワードのみが含まれ、データはリーフ ノードに格納されます。リーフ ノードはポインタを介して接続されて順序付きリンク リストを形成し、リーフ ノード上のキーワードも順序付きシーケンスを形成します。B+ ツリーの非リーフ ノードはインデックス作成にのみ使用され、データは保存されないため、非リーフ ノードの数が減り、メモリ使用率が向上します。 - B ツリーのノードはデータとインデックスの両方を保存するため、各ノードはより多くのデータを保存できます。これにより、ツリーの高さが減り、クエリの効率が向上します。ただし、B ツリーのノードにはデータが含まれているため、挿入および削除操作にはデータの移動と調整が必要となり、比較的時間がかかります。
B+ ツリーの非リーフ ノードはインデックス作成にのみ使用され、データは保存されないため、各ノードはより多くのインデックスを保存できます。リーフ ノードはポインタを介して接続され、順序付きリンク リストを形成します。これにより、順次アクセスを効率的に実行できます。同時に、B+ ツリーのデータはリーフ ノードにのみ格納されるため、挿入および削除操作はインデックス ノードを調整するだけで済み、比較的高速です。
B*ツリーの基本ルール
B* ツリーは B+ ツリーを変形したもので、兄弟ノードへのポインタが B+ ツリーの非ルート ノードおよび非リーフ ノードに追加されます。
B* ツリーと B+ ツリーの比較
結論: B* ツリーは B+ ツリーよりもスペース使用率が高い
B+ ツリーの分割: ノードがいっぱいの場合、新しいノードを割り当て、元のノードのデータの 1/2 を新しいノードにコピーし、最後に新しいノードのポインタを親ノードに追加します。
B* ツリーの分割: ノードがいっぱいで、次の兄弟ノードがいっぱいでない場合は、データの一部を兄弟ノードに移動し、元のノードにキーワードを挿入し、最後に親ノードの兄弟を変更します
。ノードのキーワード (兄弟ノードのキーワード範囲が変更されたため)。兄弟ノードもいっぱいの場合は、元のノードと兄弟ノードの間に新しいノードを追加し、データの 1/3 を新しいノードにコピーします。 . ポイントを指定し、最後に新しいノードのポインタを親ノードに追加します。
拡大する
B+ ツリーの挿入操作規則は次のとおりです。
挿入位置の検索: ルート ノードから開始して、B+ ツリーの検索ルールに従って挿入位置を検索します。挿入されたキーワードがすでにツリーに存在する場合は、特定の状況に応じて処理されます (置換、無視、マージなど)。
リーフ ノードに挿入: 新しいキーワードをリーフ ノードの適切な位置に挿入します。リーフノードの原因となるキーワードの数が挿入後の順序の上限を超えた場合、分割操作が実行されます。
リーフノード分割:順序の上限を超えたリーフノードを2つのノードに分割します。キーワードの半分を新しいノードに移動し、ポインタ接続を調整します。同時に、新しいノードの最小キーが親ノードに挿入されます。
親ノードの調整: リーフノードの分割により、親ノードのキーワードの数が順序の上限を超える場合、再帰的な分割操作が実行されます。順序の上限を超えた親ノードを2つのノードに分割し、親ノードの親ノードに新規ノードの最小キーを挿入します。
再帰的調整: 親ノードの分割により祖先ノードのキーワード数が順序の上限を超える場合、再帰的分割操作はルート ノードまで継続されます。
ルート ノードの分割: ルート ノードの分割によりツリーの高さが増加する場合は、新しいルート ノードを作成し、元のルート ノードを 2 つのノードに分割します。新しいルート ノードの最小キーを新しいルート ノードに挿入し、ポインタ接続を調整します。