B+tree 實現

/**
 BPlusTree.h
	
 2012/6/24--2012/7/5
 hpghy, [email protected]
 
 **/

#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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章