B树插入,无需主动拆分
这种插入算法需要一个条目,找到它所属的叶节点,然后将其插入那里。我们通过在适当的子节点上调用插入算法来递归地插入条目。此过程导致向下进入条目所属的叶节点,将条目放置在此处,然后一直返回到根节点。
有时节点是满的,即它包含2 * t – 1个条目,其中t是最小度。在这种情况下,必须拆分节点。在这种情况下,一个键成为父键并创建一个新节点。我们首先插入新密钥,使密钥总数为2 * t。我们将前t个条目保留在原始节点中,将最后(t-1)个条目传输到新节点,并将第(t + 1)个节点设置为这些节点的父节点。如果要拆分的节点是非子节点,那么我们还必须拆分子指针。具有2 * t个键的节点具有2 * t + 1个子指针。第一个(t + 1)指针保留在原始节点中,其余的t指针移至新节点。
This algorithm splits a node only when it is necessary. We first recursively call insert for appropriate child of node (in case of non-leaf node) or insert it into node (for leaf node). If the node is full, we split it, storing new child entry in newEntry and new parent key in val. These values are then inserted into the parent, which recursively splits itself in case it is also full.
Example:
We insert numbers 1 – 5 in tree. The tree becomes:
Then we insert 6, the node is full. Hence it is split into two nodes making 4 as parent.
We insert numbers 7 – 16, the tree becomes:
We insert 22 – 30, the tree becomes:
Note that now the root is full. If we insert 17 now, the root is not split as the leaf node in which 17 was inserted didn’t split. If we were following aggressive splitting, the root would have been split before we went to leaf node.
But if we insert 31, the leaf node splits, which recursively adds new entry to root. But as root is full, it needs to be split. The tree now becomes.
下面是上述方法的实现:
// 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