📜  B树插入,无需主动拆分

📅  最后修改于: 2021-04-17 11:38:02             🧑  作者: Mango

B树插入,无需主动拆分

这种插入算法需要一个条目,找到它所属的叶节点,然后将其插入那里。我们通过在适当的子节点上调用插入算法来递归地插入条目。此过程导致向下进入条目所属的叶节点,将条目放置在此处,然后一直返回到根节点。

有时节点是满的,即它包含2 * t – 1个条目,其中t是最小度。在这种情况下,必须拆分节点。在这种情况下,一个键成为父键并创建一个新节点。我们首先插入新密钥,使密钥总数为2 * t。我们将前t个条目保留在原始节点中,将最后(t-1)个条目传输到新节点,并将第(t + 1)个节点设置为这些节点的父节点。如果要拆分的节点是非子节点,那么我们还必须拆分子指针。具有2 * t个键的节点具有2 * t + 1个子指针。第一个(t + 1)指针保留在原始节点中,其余的t指针移至新节点。

下面是上述方法的实现:

// C++ implementation of the approach
#include 
#include 
using namespace std;
  
class BTreeNode {
  
    // Vector of keys
    vector keys;
  
    // Minimum degree
    int t;
  
    // Vector of child pointers
    vector C;
  
    // Is true when node is leaf, else false
    bool leaf;
  
public:
    // Constructor
    BTreeNode(int t, bool leaf);
  
    // Traversing the node and print its content
    // with tab number of tabs before
    void traverse(int tab);
  
    // Insert key into given node. If child is split, we
    // have to insert *val entry into keys vector and
    // newEntry pointer into C vector of this node
    void insert(int key, int* val,
                BTreeNode*& newEntry);
  
    // Split this node and store the new parent value in
    // *val and new node pointer in newEntry
    void split(int* val, BTreeNode*& newEntry);
  
    // Returns true if node is full
    bool isFull();
  
    // Makes new root, setting current root as its child
    BTreeNode* makeNewRoot(int val, BTreeNode* newEntry);
};
  
bool BTreeNode::isFull()
{
    // returns true if node is full
    return (this->keys.size() == 2 * t - 1);
}
  
BTreeNode::BTreeNode(int t, bool leaf)
{
    // Constructor to set value of t and leaf
    this->t = t;
    this->leaf = leaf;
}
  
// Function to print the nodes of B-Tree
void BTreeNode::traverse(int tab)
{
    int i;
    string s;
  
    // Print 'tab' number of tabs
    for (int j = 0; j < tab; j++) {
        s += '\t';
    }
    for (i = 0; i < keys.size(); i++) {
  
        // If this is not leaf, then before printing key[i]
        // traverse the subtree rooted with child C[i]
        if (leaf == false)
            C[i]->traverse(tab + 1);
        cout << s << keys[i] << endl;
    }
  
    // Print the subtree rooted with last child
    if (leaf == false) {
        C[i]->traverse(tab + 1);
    }
}
  
// Function to split the current node and store the new
// parent value is *val and new child pointer in &newEntry
// called only for splitting non-leaf node
void BTreeNode::split(int* val, BTreeNode*& newEntry)
{
  
    // Create new non leaf node
    newEntry = new BTreeNode(t, false);
  
    //(t+1)th becomes parent
    *val = this->keys[t];
  
    // Last (t-1) entries will go to new node
    for (int i = t + 1; i < 2 * t; i++) {
        newEntry->keys.push_back(this->keys[i]);
    }
  
    // This node stores first t entries
    this->keys.resize(t);
  
    // Last t entries will go to new node
    for (int i = t + 1; i <= 2 * t; i++) {
        newEntry->C.push_back(this->C[i]);
    }
  
    // This node stores first (t+1) entries
    this->C.resize(t + 1);
}
  
// Function to insert a new key in given node.
// If child of this node is split, we have to insert *val
// into keys vector and newEntry pointer into C vector
void BTreeNode::insert(int new_key, int* val,
                       BTreeNode*& newEntry)
{
  
    // Non leaf node
    if (leaf == false) {
        int i = 0;
  
        // Find first key greater than new_key
        while (i < keys.size() && new_key > keys[i])
            i++;
  
        // We have to insert new_key into left child of
        // Node with index i
        C[i]->insert(new_key, val, newEntry);
  
        // No split was done
        if (newEntry == NULL)
            return;
        if (keys.size() < 2 * t - 1) {
  
            // This node can accomodate a new key
            // and child pointer entry
            // Insert *val into key vector
            keys.insert(keys.begin() + i, *val);
  
            // Insert newEntry into C vector
            C.insert(C.begin() + i + 1, newEntry);
  
            // As this node was not split, set newEntry
            // to NULL
            newEntry = NULL;
        }
        else {
  
            // Insert *val and newentry
            keys.insert(keys.begin() + i, *val);
            C.insert(C.begin() + i + 1, newEntry);
  
            // Current node has 2*t keys, so split it
            split(val, newEntry);
        }
    }
    else {
  
        // Insert new_key in this node
        vector::iterator it;
  
        // Find correct position
        it = lower_bound(keys.begin(), keys.end(),
                         new_key);
  
        // Insert in correct position
        keys.insert(it, new_key);
  
        // If node is full
        if (keys.size() == 2 * t) {
  
            // Create new node
            newEntry = new BTreeNode(t, true);
  
            // Set (t+1)th key as parent
            *val = this->keys[t];
  
            // Insert last (t-1) keys into new node
            for (int i = t + 1; i < 2 * t; i++) {
                newEntry->keys.push_back(this->keys[i]);
            }
  
            // This node stores first t keys
            this->keys.resize(t);
        }
    }
}
  
// Function to create a new root
// setting current node as its child
BTreeNode* BTreeNode::makeNewRoot(int val, BTreeNode* newEntry)
{
    // Create new root
    BTreeNode* root = new BTreeNode(t, false);
  
    // Stores keys value
    root->keys.push_back(val);
  
    // Push child pointers
    root->C.push_back(this);
    root->C.push_back(newEntry);
    return root;
}
  
class BTree {
  
    // Root of B-Tree
    BTreeNode* root;
  
    // Minimum degree
    int t;
  
public:
    // Constructor
    BTree(int t);
  
    // Insert key
    void insert(int key);
  
    // Display the tree
    void display();
};
  
// Function to create a new BTree with
// minimum degree t
BTree::BTree(int t)
{
    root = new BTreeNode(t, true);
}
  
// Function to insert a node in the B-Tree
void BTree::insert(int key)
{
    BTreeNode* newEntry = NULL;
    int val = 0;
  
    // Insert in B-Tree
    root->insert(key, &val, newEntry);
  
    // If newEntry is not Null then root needs to be
    // split. Create new root
    if (newEntry != NULL) {
        root = root->makeNewRoot(val, newEntry);
    }
}
  
// Prints BTree
void BTree::display()
{
    root->traverse(0);
}
  
// Driver code
int main()
{
  
    // Create B-Tree
    BTree* tree = new BTree(3);
    cout << "After inserting 1 and 2" << endl;
    tree->insert(1);
    tree->insert(2);
    tree->display();
  
    cout << "After inserting 5 and 6" << endl;
    tree->insert(5);
    tree->insert(6);
    tree->display();
  
    cout << "After inserting 3 and 4" << endl;
    tree->insert(3);
    tree->insert(4);
    tree->display();
  
    return 0;
}
输出:
After inserting 1 and 2
1
2
After inserting 5 and 6
1
2
5
6
After inserting 3 and 4
    1
    2
    3
4
    5
    6