一、B-树特点
1.定义任意非叶子结点最多只有M个儿子;且M>2;
2.根结点的儿子数为[2, M];
3.除根结点以外的非叶子结点的儿子数为[M/2, M];
4.每个结点存放至少M/2-1(取上整)和至多M-1个关键字;(至少2个关键
5.非叶子结点的关键字个数=指向儿子的指针个数-1;
6.非叶子结点的关键字:K[1], K[2], …, K[M-1];且K[i] < K[i+1];
7.非叶子结点的指针:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树;
8.所有叶子结点位于同一层;
二、B+树特点
性质:B+树是B-树的变体,也是一种多路搜索树:其定义基本与B-树同,除了:
1.非叶子结点的子树指针与关键字个数相同
2.非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树(B-树是开区间);
3.为所有叶子结点增加一个链指针;
4.所有关键字都在叶子结点出现;
三、B*树特点
B*树定义了非叶子结点关键字个数至少为(2/3)*M,即块的最低使用率为2/3(代替B+树的1/2);
B+树的分裂:当一个结点满时,分配一个新的结点,并将原结点中1/2的数据复制到新结点,最后在父结点中增加新结点的指针;B+树的分裂只影响原结点和父结点,而不会影响兄弟结点,所以它不需要指向兄弟的指针;
B*树的分裂:当一个结点满时,如果它的下一个兄弟结点未满,那么将一部分数据移到兄弟结点中,再在原结点插入关键字,最后修改父结点中兄弟结点的关键字(因为兄弟结点的关键字范围改变了);如果兄弟也满了,则在原结点与兄弟结点之间增加新结点,并各复制1/3的数据到新结点,最后在父结点增加新结点的指针;
所以,B*树分配新结点的概率比B+树要低,空间使用率更高;
四、小结
B树:二叉树,每个结点只存储一个关键字,等于则命中,小于走左结点,大于走右结点;
B-树:多路搜索树,每个结点存储M/2到M个关键字,非叶子结点存储指向关键字范围的子结点;所有关键字在整颗树中出现,且只出现一次,非叶子结点可以命中;B+树:在B-树基础上,为叶子结点增加链表指针,所有关键字都在叶子结点中出现,非叶子结点作为叶子结点的索引;
B+树总是到叶子结点才命中;
B*树:在B+树基础上,为非叶子结点也增加链表指针,将结点的最低利用率从1/2提高到2/3。
下面是B树的创建与删除代码:
#include<malloc.h>#include<stdlib.h>
#include<string.h>
#include<iostream>
using namespace std;
//一棵 m 阶B_树是一棵 m 路搜索树
#define M 5
#define MAXNUM (M-1) // 4
#define MINNUM (M/2) // 2
typedef char KeyType;
typedef struct { }Record;
typedef struct
{
KeyType key;
Record *recptr;
}ElemType;
typedef struct BtNode
{
int num;
BtNode *parent;
ElemType data[M+1];
BtNode *sub[M+1];
}BtNode,*BTree;
typedef struct
{
BtNode *pnode;
int index;
bool tag;
}Result;
BtNode *_Buynode()
{
BtNode *s = (BtNode*)malloc(sizeof(BtNode));
if(s == NULL) exit(0);
memset(s,0,sizeof(BtNode));
return s;
}
void _Freenode(BtNode *ptr)
{
free(ptr);
}
Result FindValue(BtNode *ptr,KeyType kx)
{
Result res = {NULL,-1,false};
if(ptr == NULL)
{return res;}
while(ptr != NULL)
{
int i = ptr->num;
ptr->data[0].key = kx;
while(kx<ptr->data[i].key) --i;
res.pnode = ptr;
res.index = i;
if(i>0&& kx ==ptr->data[i].key)
{
res.tag = true;
break;
}
ptr = ptr->sub[i];
}
return res;
}
Result SearchValue(BtNode *ptr,KeyType kx)
{
Result res = {NULL,-1,false};
if(ptr == NULL)return res;
if(ptr != NULL)
{
int i = ptr->num;
ptr->data[0].key = kx;
while(kx<ptr->data[0].key) --i;
res.pnode = ptr;
res.index = i;
if(i>0&& kx ==ptr->data[0].key)
{
res.tag = true;
}
else if(ptr->sub[i] != NULL)
res = SearchValue(ptr->sub[i],kx);
}
return res;
}
BtNode *MakeRoot(ElemType x,BtNode *left,BtNode *right)
{ BtNode *s = _Buynode();
s->num = 1;
s->parent = NULL;
s->data[1] = x;
s->sub[0] = left;//
if(left != NULL)
left->parent = s;
s->sub[1] = right;//
if(right != NULL)
right->parent = s;
return s;
}
void Insert_Item(BtNode *ptr,int pos,ElemType x,BtNode *right)
{
for(int i = ptr->num;i>pos;i--)
{
ptr->data[i+1] = ptr->data[i];
ptr->sub[i+1] = ptr->sub[i];
}
ptr->data[pos+1] = x;
ptr->sub[pos+1] = right;
if(right != NULL)
right->parent = ptr;
ptr->num += 1;
}
ElemType Move_Item(BtNode *ptr,BtNode *s,int pos)
{
for(int i = pos+1,j=0; i<=ptr->num;++i,j++)
{
//s->data[j+1].key = ptr->data[i+1].key;
s->data[j] = ptr->data[i];
s->sub[j] = ptr->sub[i];
if(s->sub[j] != NULL)
{
s->sub[j]->parent = s;
}
}
ptr->num = MINNUM;
s->num = MINNUM;
s->parent = ptr->parent;
return s->data[0];
}
//分裂
BtNode * Splice(BtNode *ptr)
{
BtNode *s = _Buynode();
// ptr ==> s;
ElemType x = Move_Item(ptr,s,MINNUM);//将后面挪入新树s中,返回S->data[0]
if(ptr->parent == NULL)
{
return MakeRoot(x,ptr,s);
}
//
// parent ->num < MAXNUM;
//将x节点插入父树
ptr = ptr->parent;
int pos = ptr->num;
ptr->data[0]=x;
while(x.key<ptr->data[pos].key)--pos;
Insert_Item(ptr,pos,x,s);
if(ptr->num > MAXNUM)
{
return Splice(ptr);
}
return NULL;
}
bool Insert(BTree *proot,ElemType x)
{
if(proot == NULL)
{
return false;
}
if(*proot == NULL)
{
*proot = MakeRoot(x,NULL,NULL);
return true;
}
Result res = FindValue(*proot,x.key);//找插入位置
if(res.pnode == NULL||res.tag)return false;//无位置或者找到则返回
BtNode *ptr = res.pnode;
int pos = res.index;
Insert_Item(ptr,pos,x,NULL);//挪位插入
if(ptr->num > MAXNUM)
{
BtNode *newroot = Splice(ptr);
if(newroot != NULL)
{
*proot = newroot;
}
}
return true;
}
void print_node(BtNode *ptr)
{
if(ptr == NULL)
exit(0);
for(int i = 0;i<ptr->num;++i)
{
cout<<ptr->data[i].key;
}
}
BtNode *First(BtNode *ptr)
{
while(ptr != NULL && ptr->sub[0] != NULL)
{
ptr = ptr -> sub[0];
}
return ptr;
}
BtNode *Next(BtNode *ptr)
{
if(ptr == NULL)return NULL;
for(int i = 0;i<ptr->num ;++i)
{
if(ptr->sub[i] != NULL)
{
return First(ptr->sub[i]);
}
}
}
void NiceinOrder(BtNode *ptr)
{
if(ptr == NULL)
exit(0);
for(BtNode *p = First(ptr); p!=NULL;p=Next(p))
{
print_node(ptr);
}
cout<<endl;
}
void InOrder(BtNode *p)
{
if(p != NULL)
{
InOrder(p->sub[0]);
for(int i=1;i<=p->num;++i)
{
cout<<p->data[i].key;
InOrder(p->sub[i]);
}
}
}
//remove
BtNode *FindPrev(BtNode *ptr)
{
if(ptr == NULL)
return false;
int i = ptr->num;
while(ptr != NULL && ptr->sub[i] != NULL)
{
ptr = ptr->sub[i];
i = ptr->num;
}
return ptr;
}
BtNode *FindNext(BtNode *ptr)
{
if(ptr == NULL)
return false;
while(ptr != NULL && ptr->sub[0] != NULL)
{
ptr = ptr->sub[0];
}
return ptr;
}
void Del_Brch_Item(BtNode *ptr,int pos)
{
int i = 0;
for(i = pos;i < ptr->num;i++)
{
ptr->data[i] = ptr->data[i+1];
ptr->sub[i] = ptr->sub[i+1];
}
ptr->sub[i] = NULL;
ptr->num = ptr->num-1;
}
void Del_Leaf_Item(BtNode *ptr,int pos)
{
Del_Brch_Item(ptr,pos);
}
void Borrow_Leftbro_Item_Brch(BtNode *ptr,BtNode *leftbro,
BtNode *pa,int pos)
{
ptr->data[0] = pa->data[pos];
pa->data[pos] = leftbro->data[leftbro->num];
ptr->num += 1;
for(int i = ptr->num; i > 0 ;--i)
{
ptr->data[i] = ptr->data[i-1];
ptr->sub[i] = ptr->sub[i-1];
}
ptr->sub[0] = leftbro->sub[leftbro->num];
leftbro->num -= 1;
if(ptr->sub[0] != NULL)
{
ptr->sub[0]->parent = ptr;
}
}
void Borrow_Leftbro_Item_Leaf(BtNode *ptr,BtNode *leftbro,
BtNode *pa,int pos)
{
Borrow_Leftbro_Item_Brch(ptr,leftbro,pa,pos);
}
//
void Borrow_Rightbro_Item_Brch(BtNode *ptr,BtNode *rightbro,
BtNode *pa,int pos)
{
ptr->num += 1;
ptr->data[ptr->num] = pa->data[pos];
ptr->sub[ptr->num] = rightbro->sub[0];
pa->data[pos] = rightbro->data[1];
rightbro->sub[0] = rightbro->sub[1];
for(int i = 0;i<rightbro->num ;++i)
{
rightbro->data[i] = rightbro->data[i+1];
rightbro->sub[i] = rightbro->sub[i+1];
}
rightbro->num -= 1;
if(ptr->sub[ptr->num] != NULL)
{
ptr->sub[ptr->num]->parent = ptr;
}
}
void Borrow_Rightbro_Item_Leaf(BtNode *ptr,BtNode *rightbro,
BtNode *pa,int pos)
{
Borrow_Rightbro_Item_Brch(ptr,rightbro,pa,pos);
}
void Merge_Leftbro_Brch(BtNode *ptr,BtNode *leftbro,
BtNode *pa,int pos,BtNode *proot)
{
ptr->num +=1;
ptr->data[0] = pa->data[pos];
for(int i = ptr->num ;i>0;--i)
{
ptr->data[i] = ptr->data[i-1];
ptr->sub[i] = ptr->sub[i-1];
}
for(int i = leftbro->num + 1,j=1;j<ptr->num ;++i,++j)
{
leftbro->data[i] = ptr->data[j];
leftbro->sub[i] = ptr->sub[j];
if(leftbro->sub[i] != NULL)
{
leftbro->sub[i]->parent = leftbro;
}
}
leftbro->num = leftbro->num + ptr->num ;
pa->num -= 1;
if(pa->num == 0)
{
if(pa->parent == NULL)
{
proot = leftbro;
}
leftbro ->parent = pa->parent;
}
}
void Merge_Leftbro_Leaf(BtNode *ptr,BtNode *leftbro,
BtNode *pa,int pos,BtNode *proot)
{
Merge_Leftbro_Brch(ptr,leftbro,pa,pos,proot);
}
void Merge_Rightbro_Brch(BtNode *ptr,BtNode *rightbro,
BtNode *pa,int pos,BtNode *&root)
{
Merge_Leftbro_Brch(rightbro,ptr,pa,pos,root);
}
void Merge_Rightbro_Leaf(BtNode *ptr,BtNode *rightbro,
BtNode *pa,int pos,BtNode *&root)
{
Merge_Rightbro_Brch(ptr,rightbro,pa,pos,root);
}
void SearchLeftRightBrch(BtNode *ptr,BtNode *&leftbro,BtNode *&rightbro,int &ptrpos)
{
int index = 0;
BtNode *pa = ptr->parent;
if(pa != NULL && pa->sub[index] != ptr )
{
index++;
}
if(pa != NULL && index != 0)
{
leftbro = pa->sub[index-1];
}
if(pa != NULL && index != ptr->num )
{
rightbro = pa->sub[index+1];
}
ptrpos = index;
}
///
//调整叶子
BtNode *Adjust_Leaf(BtNode *ptr,BtNode *proot)
{
BtNode *leftbro = NULL, *rightbro =NULL;
BtNode *pa = ptr->parent;
int pos = ptr->num;
int ptrpos = 0;
while(ptr != NULL && ptr->parent != NULL && ptr->num < MINNUM )
{
SearchLeftRightBrch(ptr,leftbro,rightbro,ptrpos);
if(leftbro != NULL && leftbro->num < MINNUM)
{
Borrow_Leftbro_Item_Leaf(ptr,leftbro,pa,ptrpos);
}
else if(rightbro != NULL && rightbro->num < MINNUM)
{
Borrow_Rightbro_Item_Leaf(ptr,rightbro,pa,ptrpos);
}
else if(leftbro != NULL)
{
Merge_Leftbro_Leaf(ptr,leftbro,pa,pos,proot);
}
else if(rightbro != NULL)
{
Merge_Rightbro_Leaf(ptr,rightbro,pa,pos,proot);
}
else
ptr = ptr->parent;
}
return NULL;
}
//调整brouch
BtNode *Adjust_Brch(BtNode *ptr,BtNode *proot)
{
return Adjust_Leaf(ptr,proot);
}
bool Remove(BTree *proot,KeyType kx)
{
if(proot == NULL)return false;
Result res = FindValue(*proot,kx);
if(res.pnode == NULL||!res.tag)return false;
BtNode *ptr=res.pnode;
int pos = res.index;
BtNode *pv = FindPrev(ptr->sub[pos-1]);
BtNode *nt = FindNext(ptr->sub[pos]);
if(pv == NULL&&nt==NULL)
{
Del_Leaf_Item(ptr,res.index);
Adjust_Leaf(ptr,*proot);
}
else if(pv == NULL && nt != NULL)
{
ptr->data[pos] = nt->data[0];
ptr = nt;
Del_Brch_Item(ptr,0);
Adjust_Brch(ptr,*proot);
}
else if(nt == NULL && pv != NULL)
{
ptr->data[pos] = pv->data[0];
ptr = pv;
Del_Brch_Item(ptr,ptr->num);
Adjust_Brch(ptr,*proot);
}
return true;
}
//
int main()
{
KeyType arr[]={"qweertyuiopasdfghjklzxcvbnm"};
int n = sizeof(arr)/sizeof(arr[0])-1;
ElemType item;
BTree root =NULL;
for(int i = 0;i<n;++i)
{
item.key = arr[i];
item.recptr = (Record*)0x00008888;
cout<<Insert(&root,item);
}
cout<<endl;
InOrder(root);
cout<<endl;
KeyType kx;
while(cin>>kx,kx != '#')
{
cout<<Remove(&root,kx)<<" : ";
InOrder(root);
cout<<endl;
}
return 0;
}