先决条件: B +树的介绍
在本文中,我们将讨论如何在B +树中插入节点。在插入期间,必须遵循B +树的以下属性:
- 除根节点外,每个节点最多可以有M个子节点,至少ceil(M / 2)个子节点。
- 每个节点最多可以包含M – 1个密钥,最少可以包含ceil(M / 2)– 1个密钥。
- 根至少有两个孩子,至少有一个搜索关键字。
- 当节点包含超过M – 1个搜索键值时,会发生节点的插入溢出。
这里M是B +树的顺序。
在B +树中插入的步骤
- 每个元素都插入到叶节点中。因此,转到相应的叶节点。
- 仅当没有溢出时,才按升序将密钥插入叶节点。如果存在溢出,请继续执行下面提到的以下步骤,以在保持B +树属性的同时处理溢出。
插入B +树的属性
情况1:叶节点溢出
- 将叶节点拆分为两个节点。
- 第一个节点包含ceil((m-1)/ 2)值。
- 第二个节点包含剩余值。
- 将最小搜索键值从第二个节点复制到父节点。(右偏)
下图是将8插入5的B +树中的图示:
情况2:非叶节点中的溢出
- 将非叶节点拆分为两个节点。
- 第一个节点包含ceil(m / 2)-1值。
- 将剩余的最小的移到父级。
- 第二个节点包含剩余的键。
下面是将15插入5的B +树中的图示:
示例说明在B +树上的插入
问题:将以下键值6、16、26、36、46插入顺序为3的B +树中。
解决方案:
步骤1:顺序为3,因此一个节点中的顺序最多为2,因此只能有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