📜  在 B+ 树中插入

📅  最后修改于: 2021-09-06 06:04:27             🧑  作者: Mango

先决条件: B+树的介绍

在本文中,我们将讨论如何在 B+ 树中插入节点。在插入过程中,必须遵循B+ 树的以下属性:

  • 除根之外的每个节点最多可以有M个子节点,并且至少有ceil(M/2)个子节点。
  • 每个节点最多可以包含M – 1 个密钥,最少可以包含 ceil(M/2) – 1 个密钥。
  • 根至少有两个孩子和至少一个搜索关键字。
  • 当节点包含超过 M-1 个搜索键值时,就会发生插入溢出。

这里M是B+树的阶。

B+树插入步骤

  1. 每个元素都被插入到一个叶节点中。因此,转到相应的叶节点。
  2. 只有在没有溢出的情况下,才按递增顺序将键插入叶节点。如果发生溢出,请继续执行下面提到的以下步骤来处理溢出,同时保持 B+ 树属性。

插入 B+ 树的属性

案例一:叶子节点溢出

  1. 将叶节点拆分为两个节点。
  2. 第一个节点包含ceil((m-1)/2)值。
  3. 第二个节点包含剩余的值。
  4. 将最小的搜索键值从第二个节点复制到父节点。(右偏)

下图是将 8 插入 5 阶 B+ 树的示意图:

案例二:非叶子节点溢出

  1. 将非叶节点拆分为两个节点。
  2. 第一个节点包含 ceil(m/2)-1 值。
  3. 将剩余中最小的移动到父级。
  4. 第二个节点包含剩余的键。

下面是将 15 插入 5 阶 B+ 树的说明:

说明在 B+ 树上插入的示例

问题:将以下键值 6、16、26、36、46 插入阶为 3 的 B+ 树上。
解决方案:
步骤 1:顺序是 3,所以在一个节点中最多只能有 2 个搜索键值。由于插入仅发生在 B+ 树中的叶节点上,因此在节点中按递增顺序插入搜索键值 6 和 16。下面是相同的插图:

步骤2:我们不能在同一个节点中插入26 ,因为它会导致叶节点溢出,我们必须根据规则拆分叶节点。第一部分包含ceil((3-1)/2)值,即只有6 。第二个节点包含剩余的值,即1626 。然后还将最小的搜索关键字值从第二个节点复制到父节点,即16到父节点。下面是相同的插图:

第 3 步:现在下一个值是36 ,它要插入到26之后,但在该节点中,它再次导致该叶节点溢出。再次按照上述步骤拆分节点。第一部分包含ceil((3-1)/2)值,即只有16 。第二个节点包含剩余的值,即2636 。然后还将最小的搜索关键字值从第二个节点复制到父节点,即26到父节点。下面是相同的插图:
图示如下图所示。

第 4 步:现在我们必须插入 46,它将在36之后插入,但它会导致叶节点溢出。所以我们按照规则拆分节点。第一部分包含26 ,第二部分包含3646,但现在我们还必须将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