最近写了一个类似stl的btree,拿出来与大家共享一下。这个btree的用法与stl中的map非常相似。我在vc7.1和redhat(gcc 3.2)中编译成功。btree未经过严格测试,欢迎大家一起来测试完善他。
如果发现有什么问题,或者有什么建议,可以跟我联系。联系方式:[email protected]。
1.btree源码 #ifndef _LARRIN_WORKSHOP_BTREE_H #define _LARRIN_WORKSHOP_BTREE_H
#include <memory.h>
#define BEGIN_NAMESPACE namespace LarrinDSL { #define END_NAMESPACE }
#ifndef NULL #ifdef __cplusplus #define NULL 0 #else #define NULL ((void *)0) #endif #endif
BEGIN_NAMESPACE
template<class Type> struct btree_less { bool operator()(const Type& _Left, const Type& _Right) const { return _Left < _Right ; } };
template <class _first_,class _second_> struct btree_pair { /*typename*/ _first_ first ; /*typename*/ _second_ second ;
btree_pair(){}
btree_pair(/*typename*/ _first_ v1,/*typename*/ _second_ v2) { first = v1 ; second = v2; }
~btree_pair(){} };
template <class Key, class Type, unsigned int order , class Traits = btree_less<Key> > class btree { public:
typedef Key key_type ; typedef Type data_type; typedef Traits key_compare; typedef unsigned long size_type;
typedef btree_pair<key_type,data_type> value_type ;
private:
typedef btree<Key,Type,order,Traits> _btree_; static const unsigned int mid_pos = (int)(order / 2); static const unsigned int max_val_size = order - 1 ; static const unsigned int min_vals = ((order + 1) / 2) - 1 ;
struct tree_iterator;
class BTNode { friend class _btree_; friend class _btree_::tree_iterator ; int keynum ; BTNode *parent ; int sub_id ; //i am my parent's sub_id'th sun value_type *vals[order] ; //value node BTNode *subTree[order+1] ;
public:
BTNode() { memset(this,0,sizeof(BTNode)); }
~BTNode() { }
BTNode *left_sibling() { if(this->parent && this->sub_id > 0) { return this->parent->subTree[sub_id - 1]; }
return NULL ; }
BTNode *right_sibling() { if(this->parent && this->sub_id < this->parent->keynum) { return this->parent->subTree[sub_id + 1]; }
return NULL ; }
void set_parent(BTNode *p,const int sub_id) { this->parent = p ; this->sub_id = sub_id ; this->parent->subTree[sub_id] = this ; }
Key & _key_(const int idx){return vals[idx]->first ;}
bool find_in_node(const Key &key,int &pos) { if(keynum == 0) { pos = 0 ; return false ; }
pos = -1 ;
//binary search ... int top,bottom,mid ; top = 0 ; bottom = keynum == 0 ? 0 : keynum -1;
typename _btree_::key_compare less; for(;;) { mid = (top + bottom) / 2 ; if(less(key , _key_(mid))) //key < _key_(mid) { if(top >= bottom -1) { pos = mid ; return false ; }
bottom = mid - 1 ; } else if(less(_key_(mid),key)) //key > _key_(mid) { if(top == bottom) { pos = mid + 1; return false ; }
top = mid + 1 ; } else //find it { pos = mid ; return true ; } } }
void move_up(int new_key_pos,BTNode *&node,int &where) { BTNode *new_node = new BTNode ; int k = 0 ; for(int i = mid_pos + 1 ; i <= max_val_size ; i++,k++) { new_node->vals[k] = this->vals[i] ; if(this->subTree[i]) this->subTree[i]->set_parent(new_node,k); this->keynum--; new_node->keynum++; }
if(this->subTree[max_val_size+1]) this->subTree[max_val_size+1]->set_parent(new_node,k); if(new_key_pos != -1) { if(new_key_pos < mid_pos) // new key will keep it's position { new_key_pos = -1 ; //keep it's position } else if(new_key_pos > mid_pos) //new key will be move up { node = new_node ; where = where - mid_pos - 1; new_key_pos = -1 ; //keep new key's position } //else{} //new key will be moveup } if(this->parent) // have parent's { if(new_key_pos != -1) // new key is moved into parent { node = this->parent ; where = this->sub_id; }
for(int i = this->parent->keynum ; i > this->sub_id ; i--) { this->parent->vals[i] = this->parent->vals[i-1]; this->parent->subTree[i]->set_parent(this->parent,i+1); }
this->parent->vals[this->sub_id] = this->vals[mid_pos] ; --this->keynum;
new_node->set_parent(this->parent,this->sub_id+1);
if(++this->parent->keynum > max_val_size) { this->parent->move_up(new_key_pos,node,where); } } else // i am the current root { BTNode *new_root = new BTNode ; new_root->vals[0] = this->vals[mid_pos]; --this->keynum; ++new_root->keynum ;
if(new_key_pos != -1) { node = new_root ; where = 0 ; }
this->set_parent(new_root,0);
new_node->set_parent(new_root,1); } }
bool insert(const key_type &key,const data_type &data,BTNode *&node,int &where) { int pos ; if(find_in_node(key,pos)) //key exsist in this node already { return false ; }
if(this->subTree[pos] != NULL) { return this->subTree[pos]->insert(key,data,node,where); } else { for(int i = this->keynum ; i > pos; i--) { this->vals[i] = this->vals[i-1] ; }
{//where the new key is inserted node = this ; where = pos ; } vals[pos] = new value_type ; vals[pos]->first = key ; vals[pos]->second = data ;
if(++this->keynum > max_val_size) //slipt this node,new key will be moved up { move_up(pos,node,where); }
return true ; } } bool find(const Key &key,BTNode *&node,int &pos) { if(find_in_node(key,pos)) { node = this ; return true ; } else { if(this->subTree[pos]) { return this->subTree[pos]->find(key,node,pos); } else { return false ; } } }
BTNode * erase(BTNode *node,int idx) { //step1 : delete the key delete node->vals[idx];
//step2 : find my successor( or former) BTNode *leaf ; { int rIdx ; if(NULL == node->subTree[idx+1]) //node is a leaf { leaf = node ; rIdx = idx ; } else { rIdx = 0 ; leaf = node->subTree[idx+1] ; while(NULL != leaf->subTree[0]) { leaf = leaf->subTree[0] ; }
node->vals[idx] = leaf->vals[0] ; //copy successor to ... }
//move for(int i = rIdx ; i < leaf->keynum - 1; i++) { leaf->vals[i] = leaf->vals[i+1]; }
leaf->keynum-- ; }
//now the key is removed,we need makes sure of balance of this tree
//case 1 if(leaf->keynum >= min_vals) return NULL;
return merge(leaf); }
BTNode * merge(BTNode *node) { //case 2 if(!node->parent) //this is root too return NULL; //case 3 { BTNode *sibling = node->left_sibling(); if(sibling && sibling->keynum > min_vals) { for(int i = node->keynum ; i > 0 ; i--) { node->vals[i] = node->vals[i-1]; if(node->subTree[i]) node->subTree[i]->set_parent(node,i+1); } node->vals[0] = node->parent->vals[node->sub_id-1]; if(sibling->subTree[sibling->keynum]) sibling->subTree[sibling->keynum]->set_parent(node,0); node->keynum++;
node->parent->vals[node->sub_id-1] = sibling->vals[sibling->keynum-1]; sibling->keynum-- ; return NULL; }
sibling = node->right_sibling(); if(sibling && sibling->keynum > min_vals) { node->vals[node->keynum] = node->parent->vals[node->sub_id]; if(sibling->subTree[0]) sibling->subTree[0]->set_parent(node,node->keynum + 1) ; node->keynum++ ;
node->parent->vals[node->sub_id] = sibling->vals[0];
for(int i = 0 ; i < sibling->keynum - 1 ;i++) { sibling->vals[i] = sibling->vals[i+1] ; //move ... if(sibling->subTree[i+1]) sibling->subTree[i+1]->set_parent(sibling,i) ; } if(sibling->subTree[sibling->keynum]) sibling->subTree[sibling->keynum]->set_parent(sibling,sibling->keynum - 1) ;
sibling->keynum--; return NULL; } }
//case 4 : do merge now { BTNode *left ,*right ; left = node->left_sibling(); if(left) { right = node ; } else { left = node ; right = node->right_sibling() ; }
//now merge left/right/parent //step1: { left->vals[left->keynum] = left->parent->vals[left->sub_id]; if(right->subTree[0]) right->subTree[0]->set_parent(left,left->keynum+1); left->keynum++; }
//step2:remove parent's valus { for(int i = left->sub_id ; i < left->parent->keynum - 1 ; i++) { left->parent->vals[i] = left->parent->vals[i+1]; if(left->parent->subTree[i+2]) left->parent->subTree[i+2]->set_parent(left->parent,i+1) ; }
left->parent->keynum--; }
//step3: merge left and right - move right into left { for(int i = 0 ; i < right->keynum ; i++) { left->vals[left->keynum] = right->vals[i]; left->keynum++; if(right->subTree[i+1]) right->subTree[i+1]->set_parent(left,left->keynum) ; }
delete right ; }
if(left->parent->keynum < min_vals) { if(left->parent->keynum == 0 && !left->parent->parent) //this is root,left become new root { delete left->parent ; left->parent = NULL ; return left ; } else { return merge(left->parent); } } } }
void destroy() { for(int i = 0 ; i < this->keynum ; i++) { delete vals[i]; }
if(this->subTree[0] == NULL) //this is a leaf { delete this ; return ; } else { for(int i = 0 ; i < this->keynum+1 ; i++) { this->subTree[i]->destroy(); } }
delete this ; } };
BTNode *m_Root ; //btree size_type m_size ;
public:
struct tree_iterator { BTNode * curNode ; int curKey ;
tree_iterator():curNode(NULL),curKey(0){} tree_iterator(BTNode *node,int key):curNode(node),curKey(key){}
value_type & operator->() const { return *(curNode->vals[curKey]); }
value_type & operator *() const { return *(curNode->vals[curKey]); }
bool operator == (const tree_iterator &it) const { return (this->curNode == it.curNode && this->curKey == it.curKey) ; }
bool operator != (const tree_iterator &it) const { return (this->curNode != it.curNode || this->curKey != it.curKey) ; }
tree_iterator & operator ++() { if(curNode->subTree[curKey+1] == NULL) { if(++curKey < curNode->keynum) { } else { //check if this is end() BTNode *node = curNode->parent ; if(node == NULL) { return *this ; //end } int tmp = curNode->sub_id; while(node && tmp >= node->keynum) { tmp = node->sub_id ; node = node->parent ; }
if(node == NULL) { return *this ; //end } curKey = tmp ; curNode = node ; } } else { curNode = curNode->subTree[curKey+1] ; while(curNode->subTree[0]) { curNode = curNode->subTree[0]; }
curKey = 0 ; }
return *this ; } };
struct const_tree_iterator { const BTNode *curNode ; int curKey ;
const_tree_iterator():curNode(NULL),curKey(0){} const_tree_iterator(const BTNode *node,int key):curNode(node),curKey(key){} };
public:
typedef tree_iterator iterator ; typedef const_tree_iterator const_iterator ;
btree():m_Root(NULL),m_size(0) { }
~btree() { clear(); }
iterator begin( ) { if(!m_Root) return iterator(NULL,-1);
BTNode *node = m_Root ; while(node->subTree[0]) { node = node->subTree[0] ; }
return tree_iterator(node,0); }
const_iterator begin( ) const { if(!m_Root) return iterator(NULL,-1);
const BTNode *node = m_Root ; while(node->subTree[0]) { node = node->subTree[0] ; }
return const_tree_iterator(node,0); }
iterator end() { if(!m_Root) return iterator(NULL,-1);
BTNode * node = m_Root ; while(node->subTree[node->keynum-1]) { node = node->subTree[node->keynum]; }
return tree_iterator(node,node->keynum); }
btree_pair<iterator,bool> insert(const Key &key,const Type & data) { typedef btree_pair<iterator,bool> ret_type ;
BTNode *node ; int pos ;
if(NULL == m_Root) { m_Root = new BTNode(); }
if(m_Root->insert(key,data,node,pos)) { while(m_Root->parent) { m_Root = m_Root->parent ; }
m_size++ ; return ret_type(iterator(node,pos),true) ; }
return ret_type(this->end(),false) ; }
Type & operator[](const Key &key) { if(!this->m_Root) { this->m_Root = new BTNode ; }
iterator it = this->find(key); if(it != this->end()) { return (*it).second ; } else { btree_pair<iterator,bool> res = this->insert(key,data_type()); return (*res.first).second ; } }
iterator find(const Key& key) { if(!m_Root) return iterator(NULL,-1); BTNode *node ; int pos ;
if(m_Root->find(key,node,pos)) { return iterator(node,pos); } else { return end(); } }
size_type erase(const Key &key) { iterator it = this->find(key); erase(it) ; return m_size ; }
void erase(iterator where) { if(where != this->end()) { BTNode *root = m_Root->erase(where.curNode,where.curKey); if(root) m_Root = root ; //wei have new root ; m_size--; } }
size_type size() { return m_size ; }
void clear() { if(m_Root) { m_Root->destroy(); } m_Root = NULL ; m_size = 0 ; }
bool empty() { return m_size == 0 ; } };
END_NAMESPACE
#endif //
2.测试程序 #include "btree.h" #include <stdio.h>
using namespace LarrinDSL ; int main() { typedef btree<char,char,5> testTree ; testTree a;
char keys[] = "agfbkdhmjesirxclntup" ; for(char *p = keys ; *p ; p++) { //btree_pair<testTree::iterator,bool> k = a.insert(*p,*p); a[*p] = *p ; }
a.erase('h'); a.erase('r'); a.erase('p'); a.erase('d');
return 0 ; }

|