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;
}