先决条件: B+树的介绍
在本文中,我们将讨论如何在 B+ 树中插入节点。在插入过程中,必须遵循B+ 树的以下属性:
- 除根之外的每个节点最多可以有M个子节点,并且至少有ceil(M/2)个子节点。
- 每个节点最多可以包含M – 1 个密钥,最少可以包含 ceil(M/2) – 1 个密钥。
- 根至少有两个孩子和至少一个搜索关键字。
- 当节点包含超过 M-1 个搜索键值时,就会发生插入溢出。
这里M是B+树的阶。
B+树插入步骤
- 每个元素都被插入到一个叶节点中。因此,转到相应的叶节点。
- 只有在没有溢出的情况下,才按递增顺序将键插入叶节点。如果发生溢出,请继续执行下面提到的以下步骤来处理溢出,同时保持 B+ 树属性。
插入 B+ 树的属性
案例一:叶子节点溢出
- 将叶节点拆分为两个节点。
- 第一个节点包含ceil((m-1)/2)值。
- 第二个节点包含剩余的值。
- 将最小的搜索键值从第二个节点复制到父节点。(右偏)
下图是将 8 插入 5 阶 B+ 树的示意图:
案例二:非叶子节点溢出
- 将非叶节点拆分为两个节点。
- 第一个节点包含 ceil(m/2)-1 值。
- 将剩余中最小的移动到父级。
- 第二个节点包含剩余的键。
下面是将 15 插入 5 阶 B+ 树的说明:
说明在 B+ 树上插入的示例
问题:将以下键值 6、16、26、36、46 插入阶为 3 的 B+ 树上。
解决方案:
步骤 1:顺序是 3,所以在一个节点中最多只能有 2 个搜索键值。由于插入仅发生在 B+ 树中的叶节点上,因此在节点中按递增顺序插入搜索键值 6 和 16。下面是相同的插图:
步骤2:我们不能在同一个节点中插入26 ,因为它会导致叶节点溢出,我们必须根据规则拆分叶节点。第一部分包含ceil((3-1)/2)值,即只有6 。第二个节点包含剩余的值,即16和26 。然后还将最小的搜索关键字值从第二个节点复制到父节点,即16到父节点。下面是相同的插图:
第 3 步:现在下一个值是36 ,它要插入到26之后,但在该节点中,它再次导致该叶节点溢出。再次按照上述步骤拆分节点。第一部分包含ceil((3-1)/2)值,即只有16 。第二个节点包含剩余的值,即26和36 。然后还将最小的搜索关键字值从第二个节点复制到父节点,即26到父节点。下面是相同的插图:
图示如下图所示。
第 4 步:现在我们必须插入 46,它将在36之后插入,但它会导致叶节点溢出。所以我们按照规则拆分节点。第一部分包含26 ,第二部分包含36和46,但现在我们还必须将36复制到父节点,但这会导致溢出,因为一个节点中只能容纳两个搜索键值。现在按照步骤处理非叶节点溢出。
第一个节点包含 ceil(3/2)-1 值,即“16”。
将剩余的最小的移动到父节点,即“26”将是新的父节点。
第二个节点包含剩余的键,即“36”,其余的叶节点保持不变。下面是相同的插图:
下面是在B+树中插入的实现:
C++
// C++ program for implementing B+ Tree
#include
#include
#include
#include
using namespace std;
int MAX = 3;
// BP node
class Node {
bool IS_LEAF;
int *key, size;
Node** ptr;
friend class BPTree;
public:
Node();
};
// BP tree
class BPTree {
Node* root;
void insertInternal(int,
Node*,
Node*);
Node* findParent(Node*, Node*);
public:
BPTree();
void search(int);
void insert(int);
void display(Node*);
Node* getRoot();
};
// Constructor of Node
Node::Node()
{
key = new int[MAX];
ptr = new Node*[MAX + 1];
}
// Initialise the BPTree Node
BPTree::BPTree()
{
root = NULL;
}
// Function to find any element
// in B+ Tree
void BPTree::search(int x)
{
// If tree is empty
if (root == NULL) {
cout << "Tree is empty\n";
}
// Traverse to find the value
else {
Node* cursor = root;
// Till we reach leaf node
while (cursor->IS_LEAF == false) {
for (int i = 0;
i < cursor->size; i++) {
// If the element to be
// found is not present
if (x < cursor->key[i]) {
cursor = cursor->ptr[i];
break;
}
// If reaches end of the
// cursor node
if (i == cursor->size - 1) {
cursor = cursor->ptr[i + 1];
break;
}
}
}
// Traverse the cursor and find
// the node with value x
for (int i = 0;
i < cursor->size; i++) {
// If found then return
if (cursor->key[i] == x) {
cout << "Found\n";
return;
}
}
// Else element is not present
cout << "Not found\n";
}
}
// Function to implement the Insert
// Operation in B+ Tree
void BPTree::insert(int x)
{
// If root is null then return
// newly created node
if (root == NULL) {
root = new Node;
root->key[0] = x;
root->IS_LEAF = true;
root->size = 1;
}
// Traverse the B+ Tree
else {
Node* cursor = root;
Node* parent;
// Till cursor reaches the
// leaf node
while (cursor->IS_LEAF
== false) {
parent = cursor;
for (int i = 0;
i < cursor->size;
i++) {
// If found the position
// where we have to insert
// node
if (x < cursor->key[i]) {
cursor
= cursor->ptr[i];
break;
}
// If reaches the end
if (i == cursor->size - 1) {
cursor
= cursor->ptr[i + 1];
break;
}
}
}
if (cursor->size < MAX) {
int i = 0;
while (x > cursor->key[i]
&& i < cursor->size) {
i++;
}
for (int j = cursor->size;
j > i; j--) {
cursor->key[j]
= cursor->key[j - 1];
}
cursor->key[i] = x;
cursor->size++;
cursor->ptr[cursor->size]
= cursor->ptr[cursor->size - 1];
cursor->ptr[cursor->size - 1] = NULL;
}
else {
// Create a newLeaf node
Node* newLeaf = new Node;
int virtualNode[MAX + 1];
// Update cursor to virtual
// node created
for (int i = 0; i < MAX; i++) {
virtualNode[i]
= cursor->key[i];
}
int i = 0, j;
// Traverse to find where the new
// node is to be inserted
while (x > virtualNode[i]
&& i < MAX) {
i++;
}
// Update the current virtual
// Node to its previous
for (int j = MAX + 1;
j > i; j--) {
virtualNode[j]
= virtualNode[j - 1];
}
virtualNode[i] = x;
newLeaf->IS_LEAF = true;
cursor->size = (MAX + 1) / 2;
newLeaf->size
= MAX + 1 - (MAX + 1) / 2;
cursor->ptr[cursor->size]
= newLeaf;
newLeaf->ptr[newLeaf->size]
= cursor->ptr[MAX];
cursor->ptr[MAX] = NULL;
// Update the current virtual
// Node's key to its previous
for (i = 0;
i < cursor->size; i++) {
cursor->key[i]
= virtualNode[i];
}
// Update the newLeaf key to
// virtual Node
for (i = 0, j = cursor->size;
i < newLeaf->size;
i++, j++) {
newLeaf->key[i]
= virtualNode[j];
}
// If cursor is the root node
if (cursor == root) {
// Create a new Node
Node* newRoot = new Node;
// Update rest field of
// B+ Tree Node
newRoot->key[0] = newLeaf->key[0];
newRoot->ptr[0] = cursor;
newRoot->ptr[1] = newLeaf;
newRoot->IS_LEAF = false;
newRoot->size = 1;
root = newRoot;
}
else {
// Recursive Call for
// insert in internal
insertInternal(newLeaf->key[0],
parent,
newLeaf);
}
}
}
}
// Function to implement the Insert
// Internal Operation in B+ Tree
void BPTree::insertInternal(int x,
Node* cursor,
Node* child)
{
// If we doesn't have overflow
if (cursor->size < MAX) {
int i = 0;
// Traverse the child node
// for current cursor node
while (x > cursor->key[i]
&& i < cursor->size) {
i++;
}
// Traverse the cursor node
// and update the current key
// to its previous node key
for (int j = cursor->size;
j > i; j--) {
cursor->key[j]
= cursor->key[j - 1];
}
// Traverse the cursor node
// and update the current ptr
// to its previous node ptr
for (int j = cursor->size + 1;
j > i + 1; j--) {
cursor->ptr[j]
= cursor->ptr[j - 1];
}
cursor->key[i] = x;
cursor->size++;
cursor->ptr[i + 1] = child;
}
// For overflow, break the node
else {
// For new Interval
Node* newInternal = new Node;
int virtualKey[MAX + 1];
Node* virtualPtr[MAX + 2];
// Insert the current list key
// of cursor node to virtualKey
for (int i = 0; i < MAX; i++) {
virtualKey[i] = cursor->key[i];
}
// Insert the current list ptr
// of cursor node to virtualPtr
for (int i = 0; i < MAX + 1; i++) {
virtualPtr[i] = cursor->ptr[i];
}
int i = 0, j;
// Traverse to find where the new
// node is to be inserted
while (x > virtualKey[i]
&& i < MAX) {
i++;
}
// Traverse the virtualKey node
// and update the current key
// to its previous node key
for (int j = MAX + 1;
j > i; j--) {
virtualKey[j]
= virtualKey[j - 1];
}
virtualKey[i] = x;
// Traverse the virtualKey node
// and update the current ptr
// to its previous node ptr
for (int j = MAX + 2;
j > i + 1; j--) {
virtualPtr[j]
= virtualPtr[j - 1];
}
virtualPtr[i + 1] = child;
newInternal->IS_LEAF = false;
cursor->size
= (MAX + 1) / 2;
newInternal->size
= MAX - (MAX + 1) / 2;
// Insert new node as an
// internal node
for (i = 0, j = cursor->size + 1;
i < newInternal->size;
i++, j++) {
newInternal->key[i]
= virtualKey[j];
}
for (i = 0, j = cursor->size + 1;
i < newInternal->size + 1;
i++, j++) {
newInternal->ptr[i]
= virtualPtr[j];
}
// If cursor is the root node
if (cursor == root) {
// Create a new root node
Node* newRoot = new Node;
// Update key value
newRoot->key[0]
= cursor->key[cursor->size];
// Update rest field of
// B+ Tree Node
newRoot->ptr[0] = cursor;
newRoot->ptr[1] = newInternal;
newRoot->IS_LEAF = false;
newRoot->size = 1;
root = newRoot;
}
else {
// Recursive Call to insert
// the data
insertInternal(cursor->key[cursor->size],
findParent(root,
cursor),
newInternal);
}
}
}
// Function to find the parent node
Node* BPTree::findParent(Node* cursor,
Node* child)
{
Node* parent;
// If cursor reaches the end of Tree
if (cursor->IS_LEAF
|| (cursor->ptr[0])->IS_LEAF) {
return NULL;
}
// Traverse the current node with
// all its child
for (int i = 0;
i < cursor->size + 1; i++) {
// Update the parent for the
// child Node
if (cursor->ptr[i] == child) {
parent = cursor;
return parent;
}
// Else recursively traverse to
// find child node
else {
parent
= findParent(cursor->ptr[i],
child);
// If parent is found, then
// return that parent node
if (parent != NULL)
return parent;
}
}
// Return parent node
return parent;
}
// Function to get the root Node
Node* BPTree::getRoot()
{
return root;
}
// Driver Code
int main()
{
BPTree node;
// Create B+ Tree
node.insert(6);
node.insert(16);
node.insert(26);
node.insert(36);
node.insert(46);
// Function Call to search node
// with value 16
node.search(16);
return 0;
}
Found
如果您想与行业专家一起参加直播课程,请参阅Geeks Classes Live