/**
BPlusTree.h
2012/6/24--2012/7/5
hpghy, 790042744@qq.com
**/
#ifndef BPLUSTREE_H_
#define BPLUSTREE_H_
#include <assert.h>
#include <queue>
#include <iostream>
using std::queue;
using std::cout;
using std::endl;
using std::ends;
//======================================================================================
class BPlusNode
{
protected:
BPlusNode* parent;
bool isLeafNode;
public:
BPlusNode( bool leaf=true ) {
parent = NULL;
isLeafNode = leaf;
}
~BPlusNode() {}
bool& Leaf() {
return isLeafNode;
}
BPlusNode*& Parent() {
return this->parent;
}
};
//======================================================================================
template < typename KeyClass, int M >
class BInternalNode: public BPlusNode
{
public:
static const int MaxKey = M-1;
static const int MinKey = (M+1)/2-1;
private:
KeyClass key[M+1]; //key count: = child count - 1;
BPlusNode* child[M+1]; //child count: = ceil[M/2] --> M;
int keyCnt;
public:
BInternalNode(): BPlusNode(false) {
keyCnt = 0;
}
~BInternalNode() {}
KeyClass& Key(int idx) { return key[idx]; }
BPlusNode*& Child(int idx) { return child[idx]; }
int& KeyCnt() { return keyCnt; }
bool IsOver() { return keyCnt > MaxKey; } //key count: ceil(m/2)-1 --> M-1
bool IsTooLittle() { return keyCnt < MinKey; }
int Search( KeyClass const& key );
void Insert( KeyClass const& key, BPlusNode * pNode );
void Delete( int );
};
/**
* find the child index where the key should insert
* Maybe the name "SearchChild" is better!
*/
template < typename KeyClass, int M >
int BInternalNode<KeyClass, M>::Search( KeyClass const& key ) {
int i, j, mid;
i = 0;
j = keyCnt-1;
while ( i < j ) {
mid = (i+j)>>1;
if ( key < this->key[mid] )
j = mid-1;
else if ( this->key[mid] < key )
i = mid+1;
else
break;
}
mid = i;
//judge:
if ( !( key < this->key[mid] ) ) {
return (mid+1);
}
return mid;
}
/*
just insert, no split
*/
template < typename KeyClass, int M >
void BInternalNode<KeyClass, M>::Insert( KeyClass const& key, BPlusNode * pNode ) {
int i;
for ( i = keyCnt; i > 0; -- i ) {
if ( this->key[i-1] < key )
break;
this->key[i] = this->key[i-1];
this->child[i+1] = this->child[i];
}
this->key[i] = key;
this->child[i+1] = pNode;
++ keyCnt;
//setting parent
pNode->Parent() = this;
}
/*
Just delete key[index] and child[index+1]
*/
template < typename KeyClass, int M >
void BInternalNode<KeyClass, M>::Delete( int idx )
{
for ( int i = idx+1; i < keyCnt; ++ i ) {
key[i-1] = key[i];
child[i] = child[i+1];
}
-- keyCnt;
}
//======================================================================================
template < typename KeyClass, typename ValueClass, int L >
class BLeafNode: public BPlusNode
{
public:
static const int MaxKey = L;
static const int MinKey = (L+1)/2;
private:
KeyClass key[L+1]; //key count == value count
ValueClass value[L+1];
BLeafNode* next;
int keyCnt;
public:
BLeafNode(): BPlusNode(true) {
keyCnt = 0;
next = NULL;
}
~BLeafNode() {}
KeyClass& Key(int idx) { return key[idx]; }
ValueClass& Value(int idx) { return value[idx]; }
BLeafNode*& Next() { return next; }
int& KeyCnt() { return keyCnt; }
bool IsOver() { return keyCnt > MaxKey; }
bool IsTooLittle() { return keyCnt < MinKey; }
int Search( KeyClass const& key );
void Insert( KeyClass const& key, ValueClass const& value );
void Delete( int );
};
/**
* -1: not exist!
*/
template < typename KeyClass, typename ValueClass, int L >
int BLeafNode<KeyClass,ValueClass,L>::Search( KeyClass const& key ) {
int i, j, mid;
i = 0;
j = keyCnt-1;
while ( i <= j ) {
mid = (i+j)>>1;
if ( key < this->key[mid] )
j = mid-1;
else if ( this->key[mid] < key )
i = mid+1;
else
return mid;
}
return -1;
}
/**
* just insert key-value at specified position;
*/
template < typename KeyClass, typename ValueClass, int L >
void BLeafNode<KeyClass,ValueClass,L>::Insert( KeyClass const& key, ValueClass const& value ) {
int i;
for ( i = keyCnt; i > 0; -- i ) {
if ( this->key[i-1] < key )
break;
this->key[i] = this->key[i-1];
this->value[i] = this->value[i-1];
}
this->key[i] = key;
this->value[i] = value;
++ keyCnt;
}
/**
*
*
**/
template < typename KeyClass, typename ValueClass, int L >
void BLeafNode<KeyClass,ValueClass,L>::Delete( int idx )
{
for ( int i = idx; i < keyCnt; ++ i )
{
key[i] = key[i+1];
value[i] = value[i+1];
}
-- keyCnt;
}
//======================================================================================
template < typename KeyClass, typename ValueClass, int M, int L=M >
class BPlusTree
{
public:
typedef BPlusNode Node;
typedef BPlusNode* PNode;
typedef BInternalNode<KeyClass,M> InternalNode;
typedef BInternalNode<KeyClass,M>* PInternalNode;
typedef BLeafNode<KeyClass, ValueClass, L> LeafNode;
typedef BLeafNode<KeyClass, ValueClass, L>* PLeafNode;
private:
PNode root;
PLeafNode head;
public:
BPlusTree();
~BPlusTree();
bool Search( KeyClass const& key, ValueClass *pValue );
bool Insert( KeyClass const& key, ValueClass const& value );
bool Delete( KeyClass const& key );
//just for test
void Print();
void PrintLevel();
void Print( PNode );
private:
void Clear( PNode );
PLeafNode Search( KeyClass const& key, int& idx );
PInternalNode SearchInternal( KeyClass const& key, int& idx );
void SplitRootNode();
void SplitLeafNode( PLeafNode );
void SplitInternalNode( PInternalNode );
void Rebalance( PLeafNode );
void Rebalance( PInternalNode );
void MergeLeafNode( PLeafNode, int );
void MergeInternalNode( PInternalNode, int );
};
//=======================================================================================
template < typename KeyClass, typename ValueClass, int M, int L >
BPlusTree<KeyClass, ValueClass, M, L>::BPlusTree() {
root = NULL;
}
template < typename KeyClass, typename ValueClass, int M, int L >
BPlusTree<KeyClass, ValueClass, M, L>::~BPlusTree() {
Clear( root );
root = head = NULL;
}
/**
* Search whether it contains the specified key, if true, return the corresponding value.
* otherwise, return false.
**/
template < typename KeyClass, typename ValueClass, int M, int L >
bool BPlusTree<KeyClass, ValueClass, M, L>::Search( KeyClass const& key, ValueClass *pValue ) {
int idx;
if ( NULL == root ) {
return false;
}
PNode p = (PNode)Search( key, idx );
if ( NULL == p || -1 == idx )
return false;
if ( NULL != pValue )
//*pValue = ((PLeafNode)p)->Value(idx);
*pValue = (static_cast<PLeafNode>(p))->Value(idx);
return true;
}
template < typename KeyClass, typename ValueClass, int M, int L >
bool BPlusTree<KeyClass, ValueClass, M, L>::Insert( KeyClass const& key,
ValueClass const& value ) {
if ( NULL == root ) {
root = new LeafNode();
head = (PLeafNode)root;
((PLeafNode)root)->Insert( key, value );
}
else {
int idx;
//idx: the position which key inserted in
PLeafNode p = Search( key, idx );
//the key exist!
if ( -1 != idx )
return false;
p->Insert( key, value );
if ( p->IsOver() )
{
if ( root == p ) //root must be a leafnode
SplitRootNode();
else
SplitLeafNode(p);
}
}
return true;
}
/**
* 1 Reach the leaf that contains the key.
* 2 Delete key from leaf:
* remove the key from leaf node.
* 2.1 if internal node contains this key, replace it by the small key in the new leaf.
* 2.2 else
* 2.2.1 Lend a key from left sibling leaf.
* 2.2.2 Lend a key form right sibling leaf.
* 2.2.3 Merge leaf and its sibling.
* for attention:
* Keep the parent of leaf contains the smallest key in the leaf.
*/
template < typename KeyClass, typename ValueClass, int M, int L >
bool BPlusTree<KeyClass, ValueClass, M, L>::Delete( KeyClass const& key ){
int idx;
PLeafNode p = Search( key, idx );
if ( NULL == p || idx < 0 )
return false;
p->Delete( idx );
if ( 0 == idx && root != p ) {
PInternalNode internal = SearchInternal( key, idx );
if ( NULL != internal && idx > -1 )
internal->Key(idx) = p->Key(0);
}
if ( p->IsTooLittle() && root != p )
{
Rebalance(p);
}
return true;
}
//just for test
template < typename KeyClass, typename ValueClass, int M, int L >
void BPlusTree<KeyClass, ValueClass, M, L>::Print() {
cout << "Print head list:" << endl;
PLeafNode p = head;
while ( NULL != p ) {
Print(p);
p = p->Next();
}
cout << endl;
}
template < typename KeyClass, typename ValueClass, int M, int L >
void BPlusTree<KeyClass, ValueClass, M, L>::Print( PNode p ) {
cout << "( ";
if ( true == p->Leaf() ) {
PLeafNode leaf = static_cast<PLeafNode>(p);
for ( int i = 0; i < leaf->KeyCnt(); ++ i )
cout << leaf->Key(i) << "--" << leaf->Value(i) << " ";
}
else {
PInternalNode inter = static_cast<PInternalNode>(p);
for ( int i = 0; i < inter->KeyCnt(); ++ i )
cout << inter->Key(i) << " ";
}
cout << ") ";
}
template < typename KeyClass, typename ValueClass, int M, int L >
void BPlusTree<KeyClass, ValueClass, M, L>::PrintLevel() {
cout << "PrintLevel:" << endl;
if ( true == root->Leaf() ) {
cout << "[ ";
Print( root );
cout << " ]" << endl;
return;
}
int i, level;
queue<PNode> q;
PNode p;
q.push( root );
q.push( NULL );
level = 0;
cout << "Level :" << level << endl;
while ( !q.empty() ) {
p = q.front();
q.pop();
if ( NULL == p ) {
++ level;
if ( !q.empty() )
q.push(NULL);
cout << endl << "Level :" << level << ends;
continue;
}
Print(p);
if ( true != p->Leaf() ) {
PInternalNode tmp = static_cast<PInternalNode>(p);
for ( i = 0; i <= tmp->KeyCnt(); ++ i )
q.push( tmp->Child(i) );
}
}
cout << endl;
}
//==============================================================================================================
//private:
template < typename KeyClass, typename ValueClass, int M, int L >
void BPlusTree<KeyClass, ValueClass, M, L>::Clear( PNode p ) {
if ( NULL == p )
return;
if ( false == p->Leaf() ) {
PInternalNode inter = static_cast<PInternalNode>(p);
for ( int i = 0; i <= inter->KeyCnt(); ++ i ) {
Clear( inter->Child(i) );
}
}
delete p;
}
/**
* If tree has the parameter key, the return the leafnode and key index;
* otherwise, set idx = -1.
**/
template < typename KeyClass, typename ValueClass, int M, int L >
typename BPlusTree<KeyClass, ValueClass, M, L>::PLeafNode
BPlusTree<KeyClass, ValueClass, M, L>::Search( KeyClass const& key, int& result ){
if ( NULL == root )
return NULL;
PNode p = root;
if ( true == root->Leaf() )
{
result = ((PLeafNode)p)->Search(key);
}
else {
int idx;
PInternalNode internal;
//internal node
while ( NULL != p && p->Leaf() == false )
{
internal = static_cast<PInternalNode>(p);
idx = internal->Search(key);
p = internal->Child(idx);
}
//leaf node
//idx = ((PLeafNode)p)->Search(key);
result = static_cast<PLeafNode>(p)->Search(key);
}
return (PLeafNode)p;
}
/**
* Search a internal node that contains the key!
* */
template < typename KeyClass, typename ValueClass, int M, int L >
typename BPlusTree<KeyClass, ValueClass, M, L>::PInternalNode
BPlusTree<KeyClass, ValueClass, M, L>::SearchInternal( KeyClass const& key, int& result ){
if ( NULL == root || true == root->Leaf() )
return NULL;
PNode p = root;
int idx;
PInternalNode internal;
while ( NULL != p && p->Leaf() == false )
{
internal = static_cast<PInternalNode>(p);
idx = internal->Search(key);
if ( idx > 0 && internal->Key(idx-1) == key ) {
result = idx-1;
return internal;
}
p = internal->Child(idx);
}
result = -1;
return NULL;
}
//root must be a leafnode
template < typename KeyClass, typename ValueClass, int M, int L >
void BPlusTree<KeyClass, ValueClass, M, L>::SplitRootNode()
{
PLeafNode pRNode;
PLeafNode p = (PLeafNode)root;
int i, left, right;
pRNode = new LeafNode();
left = (L+1)>>1;
right = p->KeyCnt() - left;
for ( i = 0; i < right; ++ i ) {
pRNode->Key(i) = p->Key(i+left);
pRNode->Value(i) = p->Value(i+left);
}
pRNode->Next() = NULL;
p->Next() = pRNode;
pRNode->KeyCnt() = right;
p->KeyCnt() = left;
PInternalNode newRoot = new InternalNode();
p->Parent() = newRoot;
pRNode->Parent() = newRoot;
newRoot->Key(0) = pRNode->Key(0);
newRoot->Child(0) = root;
newRoot->Child(1) = pRNode;
newRoot->KeyCnt() = 1;
//head = (BPlusNode)root;
root = newRoot;
}
template < typename KeyClass, typename ValueClass, int M, int L >
void BPlusTree<KeyClass, ValueClass, M, L>::SplitLeafNode( PLeafNode p )
{
PLeafNode pRNode = new LeafNode();
int i, left, right;
left = (L+1)>>1;
right = p->KeyCnt() - left;
for ( i = 0; i < right; ++ i ) {
pRNode->Key(i) = p->Key(i+left);
pRNode->Value(i) = p->Value(i+left);
}
pRNode->Next() = p->Next();
p->Next() = pRNode;
pRNode->KeyCnt() = right;
p->KeyCnt() = left;
if ( NULL !=p->Parent() ) {
PInternalNode tmp = static_cast<PInternalNode>( p->Parent() );
tmp->Insert( pRNode->Key(0), pRNode );
if ( tmp->IsOver() ) {
SplitInternalNode( tmp );
}
}
else {
PInternalNode newRoot = new InternalNode();
newRoot->KeyCnt() = 1;
newRoot->Child(0) = p;
newRoot->Child(1) = pRNode;
newRoot->Key(0) = pRNode->Key(0);
p->Parent() = newRoot;
pRNode->Parent() = newRoot;
root = newRoot;
}
}
/*
SplitInternalNode()
1 Node ==> Left( ceil(M/2)-1 ) + Key(中间) + Right( M/2 )
2 InsertInternalNode( Key, Right )
*/
template < typename KeyClass, typename ValueClass, int M, int L >
void BPlusTree<KeyClass, ValueClass, M, L>::SplitInternalNode( PInternalNode p )
{
int leftK, rightK, i;
KeyClass midkey;
leftK = (M+1)/2-1;
rightK = M/2;
midkey = p->Key(leftK);
PInternalNode pRNode = new InternalNode();
for ( i = 0; i < rightK; ++ i ) {
pRNode->Key(i) = p->Key( i+leftK+1 );
pRNode->Child(i) = p->Child( i+leftK+1 );
}
pRNode->Child(rightK) = p->Child( p->KeyCnt() );
pRNode->KeyCnt() = rightK;
p->KeyCnt() = leftK;
for ( i = 0; i < pRNode->KeyCnt()+1; ++ i ) {
pRNode->Child(i)->Parent() = pRNode;
}
if ( NULL != p->Parent() ) {
PInternalNode tmp = static_cast<PInternalNode>( p->Parent() );
tmp->Insert( midkey, pRNode );
if ( tmp->IsOver() ) {
SplitInternalNode( tmp );
}
}
else {
PInternalNode newRoot = new InternalNode();
newRoot->KeyCnt() = 1;
newRoot->Child(0) = p;
newRoot->Child(1) = pRNode;
newRoot->Key(0) = midkey;
p->Parent() = newRoot;
pRNode->Parent() = newRoot;
root = newRoot;
}
}
/*
*/
template < typename KeyClass, typename ValueClass, int M, int L >
void BPlusTree<KeyClass, ValueClass, M, L>::Rebalance( PLeafNode p )
{
int index, i;
PInternalNode pa;
PLeafNode prev, next;
pa = static_cast<PInternalNode>( p->Parent() );
index = pa->Search( p->Key(0) ); //index: child pointer index!
//attention:
// prev and next node must have the same parent node!
prev = next = NULL;
if ( index != 0 )
prev = static_cast<PLeafNode>( pa->Child(index-1) );
if ( index < pa->KeyCnt() )
next = static_cast<PLeafNode>( pa->Child(index+1) );
if ( NULL != next && next->KeyCnt() > LeafNode::MinKey ) {
p->Key( p->KeyCnt() ) = next->Key(0); // pa->Key(index) == next->Key(0)
p->Value( p->KeyCnt() ) = next->Value(0);
++ p->KeyCnt();
for ( i = 1; i < next->KeyCnt(); ++ i ) {
next->Key(i-1) = next->Key(i);
next->Value(i-1) = next->Value(i);
}
-- next->KeyCnt();
pa->Key( index ) = next->Key(0);
}
else if ( NULL != prev && prev->KeyCnt() > LeafNode::MinKey ) {
for ( i = p->KeyCnt()-1; i >= 0; -- i ) {
p->Key(i+1) = p->Key(i);
p->Value(i+1) = p->Value(i);
}
p->Key(0) = prev->Key( prev->KeyCnt()-1 );
p->Value(0) = prev->Value( prev->KeyCnt()-1 );
++ p->KeyCnt();
-- prev->KeyCnt();
pa->Key(index-1) = p->Key(0);
}
else {
MergeLeafNode( p, index );
}
}
template < typename KeyClass, typename ValueClass, int M, int L >
void BPlusTree<KeyClass, ValueClass, M, L>::Rebalance( PInternalNode p )
{
int index, i;
PInternalNode pa, prev, next;
pa = static_cast<PInternalNode>( p->Parent() );
index = pa->Search( p->Key(0) ); //index: child pointer index!
prev = next = NULL;
if ( index < pa->KeyCnt() )
next = static_cast<PInternalNode>( pa->Child(index+1) );
if ( index > 0 )
prev = static_cast<PInternalNode>( pa->Child(index-1) );
if ( NULL != next && next->KeyCnt() > InternalNode::MinKey ) {
p->Key( p->KeyCnt() ) = pa->Key( index );
pa->Key( index ) = next->Key(0);
p->Child( p->KeyCnt()+1 ) = next->Child(0);
p->Child( p->KeyCnt()+1 )->Parent() = p;
++ p->KeyCnt();
for ( i = 1; i < next->KeyCnt(); ++ i ) {
next->Key(i-1) = next->Key(i);
next->Child(i-1) = next->Child(i);
}
next->Child( next->KeyCnt()-1 ) = next->Child( next->KeyCnt() );
-- next->KeyCnt();
}
else if ( NULL != prev && prev->KeyCnt() > InternalNode::MinKey ) {
for ( i = p->KeyCnt()-1; i >= 0; -- i ) {
p->Key(i+1) = p->Key(i);
p->Child(i+2) = p->Child(i+1);
}
p->Child(1) = p->Child(0);
p->Key(0) = pa->Key( index-1 );
pa->Key( index-1 ) = prev->Key( prev->KeyCnt()-1 );
p->Child(0) = prev->Child( prev->KeyCnt() );
p->Child(0)->Parent() = p;
++ p->KeyCnt();
-- prev->KeyCnt();
}
else {
MergeInternalNode( p, index );
}
}
/
/*
p->Parent()->Child(idx) == p
*/
template < typename KeyClass, typename ValueClass, int M, int L >
void BPlusTree<KeyClass, ValueClass, M, L>::MergeLeafNode( PLeafNode p, int idx )
{
PLeafNode next, prev, first, second;
PInternalNode pa;
int i, pos;
pos = -1;
pa = static_cast<PInternalNode>( p->Parent() );
prev = next = NULL;
//attention: prev and next must have the same parent node.
if ( idx != 0 )
prev = static_cast<PLeafNode>( pa->Child(idx-1) );
if ( idx < pa->KeyCnt() )
next = static_cast<PLeafNode>( pa->Child(idx+1) );
if ( NULL != next ) {
pos = idx;
first = p;
second = next;
}
else if ( idx > 0 ) {
pos = idx-1;
first = prev;
second = p;
}
for ( i = 0; i < second->KeyCnt(); ++ i ) {
first->Key( first->KeyCnt()+i ) = second->Key(i);
first->Value( first->KeyCnt()+i ) = second->Value(i);
}
first->KeyCnt() += second->KeyCnt();
first->Next() = second->Next();
pa->Delete( pos ); //remove key[pos] and child[pos+1]
delete second;
if ( root == pa && 0 == pa->KeyCnt() ) {
root = first;
delete pa;
}
else if ( pa->IsTooLittle() && root != pa ) {
Rebalance( pa );
}
}
/*
p->Parent()->Child(idx) == p
*/
template < typename KeyClass, typename ValueClass, int M, int L >
void BPlusTree<KeyClass, ValueClass, M, L>::MergeInternalNode( PInternalNode p, int idx )
{
PInternalNode next, prev, first, second, pa;
int i, pos;
pa = static_cast<PInternalNode>( p->Parent() );
prev = next = NULL;
pos = -1;
if ( idx < pa->KeyCnt() )
next = static_cast<PInternalNode>( pa->Child(idx+1) );
if ( idx > 0 )
prev = static_cast<PInternalNode>( pa->Child(idx-1) );
if ( NULL != next ) {
pos = idx;
first = p;
second = next;
}
else {
pos = idx-1;
first = prev;
second = p;
}
first->Key( first->KeyCnt() ) = pa->Key( pos );
for ( i = 0; i < second->KeyCnt(); ++ i ) {
first->Key( first->KeyCnt()+1+i ) = second->Key(i);
first->Child( first->KeyCnt()+1+i ) = second->Child(i);
second->Child(i)->Parent() = first;
}
first->KeyCnt() += second->KeyCnt() + 1;
first->Child( first->KeyCnt() ) = second->Child( second->KeyCnt() );
second->Child( second->KeyCnt() )->Parent() = first;
pa->Delete( pos ); //remove key[pos] and child[pos+1]
delete second;
if ( root == pa && 0 == pa->KeyCnt() ) {
root = first;
delete pa;
}
else if ( pa->IsTooLittle() && root != pa ) {
Rebalance( pa );
}
}
#endif
B+tree 实现
最新推荐文章于 2024-06-25 20:59:26 发布