B树:
BTreeNode.h
#include<iostream> using namespace std; class BTree; class BTreenode { private: friend BTree; //存放键值的数组 int * pkey; //当前有多少键值 int currentsize; //最大存放的键值 int maxsize; BTreenode* parent; //存放子女的数组 BTreenode** pchild; //键值初始化数值 static const int Infinity=10000; public: BTreenode():currentsize(0),maxsize(0),pchild(NULL),parent(NULL){} BTreenode(int size):currentsize(0),maxsize(size),pchild(NULL),parent(NULL) { //关键字为什么要多开辟一个 pkey=new int [size+1]; pchild=new BTreenode*[size+1]; for(int i=0;i<=size;i++) { pkey[i]=this->Infinity; pchild[i]=NULL; } } ~BTreenode() { if(maxsize) { delete []pkey; for(int i=0;i<=maxsize;i++) { pchild[i]=NULL; } } } bool IsFull() { return currentsize==maxsize; } int GetKey(int i) { if(this) return this->pkey[i]; return -1; } void Destory(BTreenode *node) { if(node==NULL) return ; for(int i=0;i<node->maxsize;i++) { Destory(node->pchild[i]); } delete node; } }; struct Triple { BTreenode*pfind; int pfindkey; bool tag; };
BTree.h
#include"BTreenode.h" class BTree { private: int Maxsize; BTreenode* root; public: BTree(int size):Maxsize(size),root(NULL) {} ~BTree() { root->Destory(root); } Triple Search(int num); int Size(); int Size(BTreenode*node); bool Insert(int num); bool Remove(int num); void Print(); BTreenode*GetParent(int num); private: void InsertKey(BTreenode*pintsert,int n,const int item,BTreenode* pright); void PreMove(BTreenode*root,int n); void Merge(BTreenode*pleft,BTreenode*pright,BTreenode*parent,int n); void LeftAdjust(BTreenode *pright, BTreenode *pparent, int min, int n); void RightAdjust(BTreenode *pleft, BTreenode *pparent, int min, int n); void Print(BTreenode *start, int n = 0); }; Triple BTree::Search(int num) { BTreenode*p=root,*q=NULL; Triple result; int i=0; while(p) { i=-1; while(num>p->pkey[++i]); if(num==p->pkey[i]) { //返回找到的节点 result.pfind=p; //返回找到的位置 result.pfindkey=i; //标记找到此数字 result.tag=1; return result; } q=p; p=p->pchild[i]; } result.pfind=q; result.pfindkey=i; result.tag=0; return result; } //在节点pintsert中的n的地方插入关键字item,使该关键字的对应的指针指向pright void BTree::InsertKey(BTreenode*pintsert,int n,const int item,BTreenode* pright) { pintsert->currentsize++; int i; for(i=pintsert->currentsize;i>n;i--) { pintsert->pkey[i]=pintsert->pkey[i-1]; } pintsert->pkey[n]=item; pintsert->pchild[n+1]=pright; if(pintsert->pchild[n+1]) { //将新插入的节点的父母指向pintsert pintsert->pchild[n+1]->parent=pintsert; for(i=0;i<=pintsert->pchild[n+1]->currentsize;i++) { //将新插入的节点的子女的父母指向新插入的节点 if(pintsert->pchild[n+1]->pchild[i]) { pintsert->pchild[n+1]->pchild[i]->parent=pintsert->pchild[n+1]; } } } } //插入节点比较麻烦,因为我们将num的节点插入叶子节点之后,如果该节点满了, //就要把父节点从中间分开,并且将中间节点放到父父节点中,依次往上类推。知道遇到没有满的节点为止 //如果都满了,则插入失败 bool BTree::Insert(int num) { //如果该树是空的,建立根节点 if(root==NULL) { root=new BTreenode(this->Maxsize); root->currentsize=1; root->pkey[1]=root->pkey[0]; root->pkey[0]=num; root->pchild[0]=root->pchild[1]=NULL; return 1; } //如果不是空的,则查找树中有没有该数字 Triple find=this->Search(num); //如果有,则插入失败 if(find.tag==1) { cout<<"the "<<num<<"has exit!"<<endl; return 0; } //pinsert为num该插入到该节点 BTreenode* pinsert=find.pfind,*newnode; BTreenode* pright=NULL,*pparent; int key=num; int n=find.pfindkey; while(1) { //如果pinsert没有满,则直接插入 if(pinsert->currentsize<pinsert->maxsize-1) { InsertKey(pinsert,n,key,pright); return 1; } //如果满了则先插入,再将该节点从中间分开,m为要分开的节点 int m=(pinsert->currentsize+1)/2; InsertKey(pinsert,n,key,pright); //newnode指向分开的节点的后半部分 newnode=new BTreenode(this->Maxsize); //开始分裂,即将pinsert节点的后半部分分配给newnode for(int i=m+1;i<=pinsert->currentsize;i++) { newnode->pkey[i-m-1]=pinsert->pkey[i]; newnode->pchild[i-m-1]=pinsert->pchild[i]; pinsert->pkey[i]=pinsert->Infinity; pinsert->pchild[i]=NULL; } //改变newnode和pinsert节点存储键值的大小 newnode->currentsize=pinsert->currentsize-m-1; pinsert->currentsize=m; //改变newnode子节点的父母 for(int i=0;i<=newnode->currentsize;i++) { if(newnode->pchild[i]) { newnode->pchild[i]->parent=newnode; for(int j=0;j<newnode->pchild[i]->currentsize;j++) { if(newnode->pchild[i]->pchild[j]) { newnode->pchild[i]->pchild[j]->parent=newnode->pchild[i]; } } } } //改变pinsert节点的父母 for(int i=0;i<=pinsert->currentsize;i++) { if(pinsert->pchild[i]) { pinsert->pchild[i]->parent=pinsert; for(int j=0;j<pinsert->pchild[i]->currentsize;j++) { if(pinsert->pchild[i]->pchild[j]) { pinsert->pchild[i]->pchild[j]->parent=pinsert->pchild[i]; } } } } //对刚刚分裂出的第m个键值我们要插入到其父母节点中 key=pinsert->pkey[m]; pright=newnode; //如果pinsert不是root节点,则从父母节点中找到适合插入m的位置,标记为n, //而要插入的节点pinsert这是变成了其父母节点,pright就是newnode if(pinsert->parent) { pparent=pinsert->parent; n=-1; pparent->pkey[pparent->currentsize]=pparent->Infinity; while(key>pparent->pkey[++n]); newnode->parent=pinsert->parent; pinsert=pparent; } //如过pinsert是root节点,则新创建一个根节点,并将pinsert和newnode作为root的孩子 else { root = new BTreenode(this->Maxsize); root->currentsize= 1; root->pkey[1] = root->pkey[0]; root->pkey[0] = key; root->pchild[0] = pinsert; root->pchild[1] = pright; newnode->parent = pinsert->parent = root; return 1; } } } //将键值和指针前移,该函数在删除中用到 void BTree::PreMove(BTreenode *root, int n) { root->pkey[root->currentsize] = root->Infinity; for (int i=n; i<root->currentsize; i++) { root->pkey[i] = root->pkey[i+1]; root->pchild[i+1] = root->pchild[i+2]; } root->currentsize--; } //合并两个子树 void BTree::Merge(BTreenode *pleft, BTreenode *pparent, BTreenode *pright, int n) { pleft->pkey[pleft->currentsize] = pparent->pkey[n]; BTreenode *ptemp; for (int i=0; i<=pright->currentsize; i++){ //merge the two child tree and the parent pleft->pkey[pleft->currentsize+i+1] = pright->pkey[i]; pleft->pchild[pleft->currentsize+i+1] = pright->pchild[i]; ptemp = pleft->pchild[pleft->currentsize+i+1]; if (ptemp){ //change thd right child tree's parent ptemp->parent = pleft; for (int j=0; j<=ptemp->currentsize; j++){ if (ptemp->pchild[j]){ ptemp->pchild[j]->parent = ptemp; } } } } pleft->currentsize = pleft->currentsize + pright->currentsize + 1; delete pright; PreMove(pparent, n); // this->Print(); } void BTree::LeftAdjust(BTreenode *pright, BTreenode *pparent, int min, int n){ BTreenode *pleft = pparent->pchild[n-1], *ptemp; if (pleft->currentsize > min-1){ for (int i=pright->currentsize+1; i>0; i--){ pright->pkey[i] = pright->pkey[i-1]; pright->pchild[i] = pright->pchild[i-1]; } pright->pkey[0] = pparent->pkey[n-1]; pright->pchild[0] = pleft->pchild[pleft->currentsize]; ptemp = pright->pchild[0]; if (ptemp){ //change the tree's parent which is moved ptemp->parent = pright; for (int i=0; i<ptemp->currentsize; i++){ if (ptemp->pchild[i]){ ptemp->pchild[i]->parent = ptemp; } } } pparent->pkey[n-1] = pleft->pkey[pleft->currentsize-1]; pleft->pkey[pleft->currentsize] = pleft->Infinity; pleft->currentsize--; pright->currentsize++; } else { Merge(pleft, pparent, pright, n-1); } // this->Print(); } void BTree::RightAdjust(BTreenode *pleft, BTreenode *pparent, int min, int n){ BTreenode *pright = pparent->pchild[1], *ptemp; if (pright && pright->currentsize > min-1){ pleft->pkey[pleft->currentsize] = pparent->pkey[0]; pparent->pkey[0] = pright->pkey[0]; pleft->pchild[pleft->currentsize+1] = pright->pchild[0]; ptemp = pleft->pchild[pleft->currentsize+1]; if (ptemp){ //change the tree's parent which is moved ptemp->parent = pleft; for (int i=0; i<ptemp->currentsize; i++){ if (ptemp->pchild[i]){ ptemp->pchild[i]->parent = ptemp; } } } pright->pchild[0] = pright->pchild[1]; pleft->currentsize++; PreMove(pright,0); } else { Merge(pleft, pparent, pright, 0); } } bool BTree::Remove(const int item){ Triple result = this->Search(item); if (!result.tag){ return 0; } BTreenode *pdel, *pparent, *pmin; int n = result.pfindkey; pdel = result.pfind; if (pdel->pchild[n+1] != NULL){ //change into delete leafnode pmin = pdel->pchild[n+1]; pparent = pdel; while (pmin != NULL){ pparent = pmin; pmin = pmin->pchild[0]; } pdel->pkey[n] = pparent->pkey[0]; pdel = pparent; n = 0; } PreMove(pdel, n); //delete the node int min = (this->Maxsize + 1) / 2; while (pdel->currentsize < min-1){ //if it is not a BTree, then adjust n = 0; pparent = pdel->parent; if (NULL == pparent) { return 1; } while (n<= pparent->currentsize && pparent->pchild[n]!=pdel){ n++; } if (!n){ RightAdjust(pdel, pparent, min, n); //adjust with the parent and the right child tree } else { LeftAdjust(pdel, pparent, min, n); //adjust with the parent and the left child tree } pdel = pparent; if (pdel == root){ break; } } if (!root->currentsize){ //the root is merged pdel = root->pchild[0]; delete root; root = pdel; root->parent = NULL; for (int i=0; i<root->currentsize; i++){ if (root->pchild[i]){ root->pchild[i]->parent = root; } } } return 1; } void BTree::Print(BTreenode *start, int n){ if (NULL == start){ return; } if (start->pchild[0]){ Print(start->pchild[0], n+1); //print the first child tree } else { for (int j=0; j<n; j++){ cout << " "; } cout << "NULL" << endl; } for (int i=0; i<start->currentsize; i++){ //print the orther child tree for (int j=0; j<n; j++){ cout << " "; } cout << start->pkey[i] << "--->" <<endl; if (start->pchild[i+1]){ Print(start->pchild[i+1], n+1); } else { for (int j=0; j<n; j++){ cout << " "; } cout << "NULL" << endl; } } } void BTree::Print(){ Print(root); } int BTree::Size(BTreenode *root){ if (NULL == root){ return 0; } int size=root->currentsize; for (int i=0; i<=root->currentsize; i++){ if (root->pchild[i]){ size += this->Size(root->pchild[i]); } } return size; } int BTree::Size(){ return this->Size(this->root); } BTreenode* BTree::GetParent(const int item){ Triple result = this->Search(item); return result.pfind->parent; }
test.cpp
#include"BTree.h" int main(){ BTree btree(3); int init[]={1,3,5,7,4,2,8,0,6,9,29,13,25,11,32,55,34,22,76,45 ,14,26,33,88,87,92,44,54,23,12,21,99,19,27,57,18,72,124,158,234 ,187,218,382,122,111,222,333,872,123}; for (int i=0; i<49; i++){ btree.Insert(init[i]); } btree.Print(); cout << endl << endl << endl; Triple result = btree.Search(13); cout << result.pfind->GetKey(result.pfindkey) << endl; cout << endl << endl << endl; for (int i=0; i<49; i++){ btree.Remove(init[i]); btree.Print(); cout << endl << endl << endl; } return 0; }