📜  插入B +树

📅  最后修改于: 2021-05-05 01:51:59             🧑  作者: Mango

先决条件: B +树的介绍

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

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

这里M是B +树的顺序。

在B +树中插入的步骤

  1. 每个元素都插入到叶节点中。因此,转到相应的叶节点。
  2. 仅当没有溢出时,才按升序将密钥插入叶节点。如果存在溢出,请继续执行下面提到的以下步骤,以在保持B +树属性的同时处理溢出。

插入B +树的属性

情况1:叶节点溢出

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

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

情况2:非叶节点中的溢出

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

下面是将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 。第二节点包含剩余值,即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