B+树的插入、删除(附源代码)
B+ Tree
Index
Basic
B+树和B树类似(有关B树:http://www.cnblogs.com/YuNanlong/p/6354029.html,区别主要在于叶节点,如果在父节点的Child
数组中指向某一叶节点指针的下标为Index,则该叶节点中的最大数据值与其父节点中Key[Index]
的值相等,并且除最右侧的叶节点之外所有叶节点都有一个指针指向其右边的兄弟节点,因此所有非叶节点中数据值都在叶节点中有相同的值与之对应。
下面是一些声明和定义:
typedef int ElementType;
typedef int* PtrElementType;
typedef enum Bool BoolType;
enum Bool{
False = 0,
True = 1
};
typedef struct TreeNode *PtrBpNode;
typedef struct TreeNode BpNode;
struct TreeNode{
int Num;
BoolType IsLeaf;
PtrElementType Key;
PtrBpNode *Child;
PtrBpNode Next;
};
typedef struct Tree *PtrBp;
struct Tree{
PtrBpNode Root;
};
void ShiftKey(PtrElementType Key, BoolType Direction, int Begin, int End){
int i;
if(True == Direction){
for(i = End; i >= Begin; i--){
Key[i + 1] = Key[i];
}
}
else{
for(i = Begin; i <= End; i++){
Key[i - 1] = Key[i];
}
}
}
void ShiftChild(PtrBpNode *Child, BoolType Direction, int Begin, int End){
int i;
if(True == Direction){
for(i = End; i >= Begin; i--){
Child[i + 1] = Child[i];
}
}
else{
for(i = Begin; i <= End; i++){
Child[i - 1] = Child[i];
}
}
}
int GetIndex(PtrElementType Key, int Size, ElementType Val){
int i;
for(i = 0; i < Size; i++){
if(Key[i] >= Val){
break;
}
}
return i;
}
void BpPrintTree(PtrBpNode Root){
int i;
if(NULL == Root){
return;
}
putchar('[');
for(i = 0; i < Root->Num; i++){
printf("%d", Root->Key[i]);
if(i != Root->Num - 1){
putchar(' ');
}
}
putchar(']');
printf("%d ", Root->IsLeaf);
printf("%d", Root->Num);
putchar('\n');
for(i = 0; i <= Root->Num; i++){
BpPrintTree(Root->Child[i]);
}
}
void BpCreateTree(PtrBp T){
int i;
int a[] = {12,1,9,2,0,11,7,19,4,15,18,5,14,13,10,16,6,3,8,17,20,21,23};
for(i = 0; i < 23; i++){
BpInsert(T, a[i]);
BpPrintTree(T->Root);
printf("The End\n");
}
}
Insert
B+树的插入只需要在B树插入的基础上处理叶节点的特殊情况。所以差异的部分主要是分裂节点的函数:
void BpSpilitNode(PtrBpNode SpilitNodeP, int ChildIndex){
int i;
PtrBpNode NewNode, SubNode = SpilitNodeP->Child[ChildIndex];
if(True == SubNode->IsLeaf){
NewNode = BpAllocateNode(True);
for(i = 0; i < MinDegree - 1; i++){
NewNode->Key[i] = SubNode->Key[i + MinDegree];
}
NewNode->Num = MinDegree - 1;
SubNode->Num = MinDegree;
NewNode->Next = SubNode->Next;
SubNode->Next = NewNode;
}
else{
NewNode = BpAllocateNode(False);
for(i = 0; i < MinDegree - 1; i++){
NewNode->Key[i] = SubNode->Key[i + MinDegree];
}
for(i = 0; i < MinDegree; i++){
NewNode->Child[i] = SubNode->Child[i + MinDegree];
}
NewNode->Num = SubNode->Num = MinDegree - 1;
}
ShiftKey(SpilitNodeP->Key, True, ChildIndex, SpilitNodeP->Num - 1);
ShiftChild(SpilitNodeP->Child, True, ChildIndex + 1, SpilitNodeP->Num);
SpilitNodeP->Key[ChildIndex] = SubNode->Key[MinDegree - 1];
SpilitNodeP->Child[ChildIndex + 1] = NewNode;
(SpilitNodeP->Num)++;
}
这个函数将叶节点的分裂和非叶节点的分裂作为两种情况来处理,而实际上这个函数还是可以优化的。非叶节点的分裂和B树的一样;叶节点的分裂则是将满叶节点分裂为数据量为Minimum Degree和Minimum Degree - 1的两个节点,同时将大小为Minimum Degree的节点中的最大数据(其实就是原满叶节点的数据中值)向上插入到该叶节点的父节点中,当然还需要将叶节点中指向兄弟节点的指针进行赋值,相当于是单链表中的插入操作。与B树一样,这里也需要注意对于节点结构中IsLeaf
成员的赋值。对于满叶节点的分裂,与B树的区别就在于B树是将满叶节点分裂为数据量均为Minimum Degree - 1的两个节点,因此同样是将原满叶节点的数据中值向上插入到其父节点中,B+树在执行完分裂叶节点的操作后,该数据中值仍然保留在分裂后的某一叶节点中,而B树在执行完分裂叶节点的操作后,相当于是把该数据中值从叶节点中删除了。
完整的插入操作:
PtrBpNode BpAllocateNode(BoolType IsLeaf){
int i;
PtrBpNode NewNode = (PtrBpNode)malloc(sizeof(BpNode));
NewNode->Num = 0;
if(True == IsLeaf){
NewNode->IsLeaf = True;
}
else{
NewNode->IsLeaf = False;
}
NewNode->Key = (PtrElementType)malloc(sizeof(ElementType) * (MinDegree * 2 - 1));
NewNode->Child =(PtrBpNode*)malloc(sizeof(PtrBpNode) * MinDegree * 2);
for(i = 0; i < MinDegree * 2; i++){
NewNode->Child[i] = NULL;
}
NewNode->Next = NULL;
return NewNode;
}
void BpInsert(PtrBp T, ElementType Val){
PtrBpNode NewNode;
if(MinDegree * 2 - 1 == T->Root->Num){
NewNode = BpAllocateNode(False);
NewNode->Child[0] = T->Root;
T->Root = NewNode;
BpSpilitNode(NewNode, 0);
}
BpInsertNonFull(T->Root, Val);
}
void BpInsertNonFull(PtrBpNode CurrentNode, ElementType Val){
int Index = GetIndex(CurrentNode->Key, CurrentNode->Num, Val);
if(True == CurrentNode->IsLeaf){
ShiftKey(CurrentNode->Key, True, Index, CurrentNode->Num - 1);
CurrentNode->Key[Index] = Val;
(CurrentNode->Num)++;
}
else{
if(MinDegree * 2 - 1 == CurrentNode->Child[Index]->Num){
BpSpilitNode(CurrentNode, Index);
//Caution
if(CurrentNode->Key[Index] < Val){
Index++;
}
}
BpInsertNonFull(CurrentNode->Child[Index], Val);
}
}
void BpSpilitNode(PtrBpNode SpilitNodeP, int ChildIndex){
int i;
PtrBpNode NewNode, SubNode = SpilitNodeP->Child[ChildIndex];
if(True == SubNode->IsLeaf){
NewNode = BpAllocateNode(True);
for(i = 0; i < MinDegree - 1; i++){
NewNode->Key[i] = SubNode->Key[i + MinDegree];
}
NewNode->Num = MinDegree - 1;
SubNode->Num = MinDegree;
NewNode->Next = SubNode->Next;
SubNode->Next = NewNode;
}
else{
NewNode = BpAllocateNode(False);
for(i = 0; i < MinDegree - 1; i++){
NewNode->Key[i] = SubNode->Key[i + MinDegree];
}
for(i = 0; i < MinDegree; i++){
NewNode->Child[i] = SubNode->Child[i + MinDegree];
}
NewNode->Num = SubNode->Num = MinDegree - 1;
}
ShiftKey(SpilitNodeP->Key, True, ChildIndex, SpilitNodeP->Num - 1);
ShiftChild(SpilitNodeP->Child, True, ChildIndex + 1, SpilitNodeP->Num);
SpilitNodeP->Key[ChildIndex] = SubNode->Key[MinDegree - 1];
SpilitNodeP->Child[ChildIndex + 1] = NewNode;
(SpilitNodeP->Num)++;
}
记录自己码代码过程中的一个小bug
当然以上操作中的BpInsertNonFull
函数,我自己在第一遍写的时候出过一个小bug,对于以上代码中的Caution注释行处的内层if语句块,我一开始没有将其放在外层的if语句块中,而是放在外层if语句块外面,紧接着外层if语句执行,但是应当注意到此函数中的Index
变量有可能等于数组的Size,因此如果内层if语句块放在外面,会使得无论是否执行分裂都要通过Index来访问数组(在if条件判断中),这样就可能出现越界的情况,而现在这样的处理使得只有执行分裂操作后才会通过Index来访问数组,而分裂后数组Size加1,也就不存在越界的问题了。
Delete
B+树的删除虽然有很多情况需要处理,但是其中的一部分都与B树相同,这里只记录不同于B树的情况处理,主要也是为了维护B+树叶节点的特有性质。
- 待删除数据
Val
在该节点中,且该节点的子节点是叶节点,记该节点为CurrentNode
,待删除数据Val
在该节点的Key
数组中的下标为Index,并记该节点的Child
数组中下标为Index的元素所指向的节点为Precursor
,下标为Index + 1的元素所指向的节点为Successor
。
如果
Precursor
中的数据量大于Minimum Degree - 1,用Precursor
中第二大的数据值代替CurrentNode
中的Val
,并在Precursor
中递归删除Val
。如果
Successor
中的数据量大于Minimum Degree - 1,用Successor
中的最小数据值代替CurrentNode
和Precursor
中的Val
值,并在Successor
中递归删除Val
。如果以上均不满足,则合并
Precursor
和Successor
,然后在合并后的新节点中递归删除Val
。
- 待删除数据
Val
不在该节点中,且该节点的子节点是叶节点,记该节点为CurrentNode
,待删除数据Val
在该节点的Key
数组中的下标为Index,并记该节点的Child
数组中下标为Index的元素所指向的节点为SubNode
,下标为Index - 1的元素所指向的节点为Precursor
(如果存在),下标为Index + 1的元素所指向的节点为Successor
(如果存在)。
如果
SubNode
中的数据量大于Minimum Degree - 1,则直接在SubNode
中递归删除即可。如果
SubNode
中的数据量小于或等于Minimum Degree - 1:如果
Precursor
中的数据量大于Minimum Degree - 1,则将CurrentNode
中下标为Index - 1的数据值插入SubNode
中,并将SubNode
中记录数据量的成员Num
加1,用Precursor
中的第二大数据值填入CurrentNode
中下标为Index - 1的空缺,并将Precursor
中记录数据量的成员Num
减1,最后在SubNode
中递归删除Val
。如果
Successor
中的数据量大于Minimum Degree - 1,则将Successor
中的最小数据插入SubNode
中,并将SubNode
中记录数据量的成员Num
加1,同时CurrentNode
的Key
数组中下标为Index的元素值也由Successor
中的最小数据代替,并将Successor
中Key
数组的部分元素向左移动一位,相应的Successor
中记录数据量的成员Num
也应减1,最后在SubNode
中递归删除Val
。如果以上均不符合,则将
SubNode
与Precursor
或Successor
合并(两者不一定均存在,选择存在的进行合并),然后在合并后的节点中递归删除Val
。
当然删除节点操作中的部分情况涉及移动数组的部分元素,尤其是对于内点,要注意除了Key
数组,还要移动Child
数组。
当然因为叶节点的特殊性质,合并操作也有所不同,区别就在于合并叶节点时,合并后节点的大小为Minimum Degree * 2 - 2,因为两被合并叶节点在其父节点中所夹元素同样存在于叶节点中,所以在合并中也就不需要将这个值重复插入合并节点中了。
完整的删除操作:
void BpDelete(PtrBp T, PtrBpNode CurrentNode, ElementType Val){
int Index = GetIndex(CurrentNode->Key, CurrentNode->Num, Val);
PtrBpNode Precursor, SubNode, Successor;
if(Index < CurrentNode->Num && Val == CurrentNode->Key[Index]){
if(True == CurrentNode->IsLeaf){
ShiftKey(CurrentNode->Key, False, Index + 1, CurrentNode->Num - 1);
(CurrentNode->Num)--;
return;
}
else{
Precursor = CurrentNode->Child[Index];
Successor = CurrentNode->Child[Index + 1];
if(Precursor->Num >= MinDegree){
if(True == SubNode->IsLeaf){
CurrentNode->Key[Index] = Precursor->Key[SubNode->Num - 2];
}
else{
CurrentNode->Key[Index] = Precursor->Key[SubNode->Num - 1];
}
BpDelete(T, Precursor, Precursor->Key[SubNode->Num - 1]);
}
else if(Successor->Num >= MinDegree){
CurrentNode->Key[Index] = Successor->Key[0];
if(True == SubNode->IsLeaf){
SubNode->Key[SubNode->Num - 1] = CurrentNode->Key[Index];
}
BpDelete(T, Successor, Successor->Key[0]);
}
else{
BpMerge(T, CurrentNode, Index, Index + 1);
BpDelete(T, Precursor, Val);
}
}
}
else{
if(True == CurrentNode->IsLeaf){
return;
}
else{
if(Index > 0){
Precursor = CurrentNode->Child[Index - 1];
}
SubNode = CurrentNode->Child[Index];
if(Index < CurrentNode->Num){
Successor = CurrentNode->Child[Index + 1];
}
if(SubNode->Num >= MinDegree){
BpDelete(T, SubNode, Val);
}
else{
if(Index > 0 && Precursor->Num >= MinDegree){
ShiftKey(SubNode->Key, True, 0, SubNode->Num - 1);
SubNode->Key[0] = CurrentNode->Key[Index - 1];
if(True == SubNode->IsLeaf){
CurrentNode->Key[Index - 1] = Precursor->Key[Precursor->Num - 2];
}
else{
CurrentNode->Key[Index - 1] = Precursor->Key[Precursor->Num - 1];
ShiftChild(SubNode->Child, True, 0, SubNode->Num);
SubNode->Child[0] = Precursor->Child[Precursor->Num];
}
(SubNode->Num)++;
(Precursor->Num)--;
BpDelete(T, SubNode, Val);
}
else if(Index < CurrentNode->Num && Successor->Num >= MinDegree){
if(True == SubNode->IsLeaf){
SubNode->Key[SubNode->Num] = Successor->Key[0];
}
else{
SubNode->Key[SubNode->Num] = CurrentNode->Key[Index];
}
CurrentNode->Key[Index] = Successor->Key[0];
SubNode->Child[SubNode->Num + 1] = Successor->Child[0];
(SubNode->Num)++;
ShiftKey(Successor->Key, False, 1, Successor->Num - 1);
ShiftChild(Successor->Child, False, 1, Successor->Num);
(Successor->Num)--;
BpDelete(T, SubNode, Val);
}
else{
if(Index > 0){
BpMerge(T, CurrentNode, Index - 1, Index);
BpDelete(T, Precursor, Val);
}
else{
BpMerge(T, CurrentNode, Index, Index + 1);
BpDelete(T, SubNode, Val);
}
}
}
}
}
}
void BpMerge(PtrBp T, PtrBpNode CurrentNode, int LeftIndex, int RightIndex){
int i;
PtrBpNode LeftNode = CurrentNode->Child[LeftIndex];
PtrBpNode RightNode = CurrentNode->Child[RightIndex];
if(True == LeftNode->IsLeaf){
for(i = 0; i < MinDegree - 1; i++){
LeftNode->Key[i + MinDegree - 1] = RightNode->Key[i];
}
LeftNode->Num = MinDegree * 2 - 2;
LeftNode->Next = RightNode->Next;
}
else{
for(i = 0; i < MinDegree - 1; i++){
LeftNode->Key[i + MinDegree] = RightNode->Key[i];
}
for(i = 0; i < MinDegree; i++){
LeftNode->Key[i + MinDegree] = RightNode->Key[i];
}
LeftNode->Key[MinDegree - 1] = CurrentNode->Key[LeftIndex];
LeftNode->Num = MinDegree * 2 - 1;
}
ShiftKey(CurrentNode->Key, False, LeftIndex + 1, CurrentNode->Num - 1);
ShiftChild(CurrentNode->Child, False, RightIndex + 1, CurrentNode->Num);
(CurrentNode->Num)--;
if(CurrentNode == T->Root && 0 == CurrentNode->Num){
T->Root = LeftNode;
}
}
Source Code
#include <stdio.h>
#include <stdlib.h>
#define MinDegree 4
typedef int ElementType;
typedef int* PtrElementType;
typedef enum Bool BoolType;
enum Bool{
False = 0,
True = 1
};
typedef struct TreeNode *PtrBpNode;
typedef struct TreeNode BpNode;
struct TreeNode{
int Num;
BoolType IsLeaf;
PtrElementType Key;
PtrBpNode *Child;
PtrBpNode Next;
};
typedef struct Tree *PtrBp;
struct Tree{
PtrBpNode Root;
};
PtrBpNode BpAllocateNode(BoolType IsLeaf);
void BpSpilitNode(PtrBpNode SpilitNodeP, int ChildIndex);
void BpInsertNonFull(PtrBpNode CurrentNode, ElementType Val);
void BpInsert(PtrBp T, ElementType Val);
void BpMerge(PtrBp T, PtrBpNode CurrentNode, int LeftIndex, int RightIndex);
void BpDelete(PtrBp T, PtrBpNode CurrentNode, ElementType Val);
void ShiftKey(PtrElementType Key, BoolType Direction, int Begin, int End);
void ShiftChild(PtrBpNode *Child, BoolType Direction, int Begin, int End);
int GetIndex(PtrElementType Key, int Size, ElementType Val);
void BpPrintTree(PtrBpNode Root);
void BpCreateTree(PtrBp T);
int main(){
PtrBp T = (PtrBp)malloc(sizeof(struct Tree));
T->Root = BpAllocateNode(True);
BpCreateTree(T);
//printf("B_Tree after delete 11:\n");
//BTDelete(T, T->Root, 11);
//BTPrintTree(T->Root);
printf("Bp_Tree after delete 16:\n");
BpDelete(T, T->Root, 16);
BpPrintTree(T->Root);
printf("Bp_Tree after delete 18:\n");
BpDelete(T, T->Root, 18);
BpPrintTree(T->Root);
printf("Bp_Tree after delete 20:\n");
BpDelete(T, T->Root, 20);
BpPrintTree(T->Root);
printf("Bp_Tree after delete 19:\n");
BpDelete(T, T->Root, 19);
BpPrintTree(T->Root);
printf("Bp_Tree after delete 0:\n");
BpDelete(T, T->Root, 0);
BpPrintTree(T->Root);
printf("Bp_Tree after delete 5:\n");
BpDelete(T, T->Root, 5);
BpPrintTree(T->Root);
printf("Bp_Tree after delete 2:\n");
BpDelete(T, T->Root, 2);
BpPrintTree(T->Root);
return 0;
}
PtrBpNode BpAllocateNode(BoolType IsLeaf){
int i;
PtrBpNode NewNode = (PtrBpNode)malloc(sizeof(BpNode));
NewNode->Num = 0;
if(True == IsLeaf){
NewNode->IsLeaf = True;
}
else{
NewNode->IsLeaf = False;
}
NewNode->Key = (PtrElementType)malloc(sizeof(ElementType) * (MinDegree * 2 - 1));
NewNode->Child =(PtrBpNode*)malloc(sizeof(PtrBpNode) * MinDegree * 2);
for(i = 0; i < MinDegree * 2; i++){
NewNode->Child[i] = NULL;
}
NewNode->Next = NULL;
return NewNode;
}
void BpInsert(PtrBp T, ElementType Val){
PtrBpNode NewNode;
if(MinDegree * 2 - 1 == T->Root->Num){
NewNode = BpAllocateNode(False);
NewNode->Child[0] = T->Root;
T->Root = NewNode;
BpSpilitNode(NewNode, 0);
}
BpInsertNonFull(T->Root, Val);
}
void BpInsertNonFull(PtrBpNode CurrentNode, ElementType Val){
int Index = GetIndex(CurrentNode->Key, CurrentNode->Num, Val);
if(True == CurrentNode->IsLeaf){
ShiftKey(CurrentNode->Key, True, Index, CurrentNode->Num - 1);
CurrentNode->Key[Index] = Val;
(CurrentNode->Num)++;
}
else{
if(MinDegree * 2 - 1 == CurrentNode->Child[Index]->Num){
BpSpilitNode(CurrentNode, Index);
if(CurrentNode->Key[Index] < Val){
Index++;
}
}
BpInsertNonFull(CurrentNode->Child[Index], Val);
}
}
void BpSpilitNode(PtrBpNode SpilitNodeP, int ChildIndex){
int i;
PtrBpNode NewNode, SubNode = SpilitNodeP->Child[ChildIndex];
if(True == SubNode->IsLeaf){
NewNode = BpAllocateNode(True);
for(i = 0; i < MinDegree - 1; i++){
NewNode->Key[i] = SubNode->Key[i + MinDegree];
}
NewNode->Num = MinDegree - 1;
SubNode->Num = MinDegree;
NewNode->Next = SubNode->Next;
SubNode->Next = NewNode;
}
else{
NewNode = BpAllocateNode(False);
for(i = 0; i < MinDegree - 1; i++){
NewNode->Key[i] = SubNode->Key[i + MinDegree];
}
for(i = 0; i < MinDegree; i++){
NewNode->Child[i] = SubNode->Child[i + MinDegree];
}
NewNode->Num = SubNode->Num = MinDegree - 1;
}
ShiftKey(SpilitNodeP->Key, True, ChildIndex, SpilitNodeP->Num - 1);
ShiftChild(SpilitNodeP->Child, True, ChildIndex + 1, SpilitNodeP->Num);
SpilitNodeP->Key[ChildIndex] = SubNode->Key[MinDegree - 1];
SpilitNodeP->Child[ChildIndex + 1] = NewNode;
(SpilitNodeP->Num)++;
}
void ShiftKey(PtrElementType Key, BoolType Direction, int Begin, int End){
int i;
if(True == Direction){
for(i = End; i >= Begin; i--){
Key[i + 1] = Key[i];
}
}
else{
for(i = Begin; i <= End; i++){
Key[i - 1] = Key[i];
}
}
}
void ShiftChild(PtrBpNode *Child, BoolType Direction, int Begin, int End){
int i;
if(True == Direction){
for(i = End; i >= Begin; i--){
Child[i + 1] = Child[i];
}
}
else{
for(i = Begin; i <= End; i++){
Child[i - 1] = Child[i];
}
}
}
int GetIndex(PtrElementType Key, int Size, ElementType Val){
int i;
for(i = 0; i < Size; i++){
if(Key[i] >= Val){
break;
}
}
return i;
}
void BpDelete(PtrBp T, PtrBpNode CurrentNode, ElementType Val){
int Index = GetIndex(CurrentNode->Key, CurrentNode->Num, Val);
PtrBpNode Precursor, SubNode, Successor;
if(Index < CurrentNode->Num && Val == CurrentNode->Key[Index]){
if(True == CurrentNode->IsLeaf){
ShiftKey(CurrentNode->Key, False, Index + 1, CurrentNode->Num - 1);
(CurrentNode->Num)--;
return;
}
else{
Precursor = CurrentNode->Child[Index];
Successor = CurrentNode->Child[Index + 1];
if(Precursor->Num >= MinDegree){
if(True == SubNode->IsLeaf){
CurrentNode->Key[Index] = Precursor->Key[SubNode->Num - 2];
}
else{
CurrentNode->Key[Index] = Precursor->Key[SubNode->Num - 1];
}
BpDelete(T, Precursor, Precursor->Key[SubNode->Num - 1]);
}
else if(Successor->Num >= MinDegree){
CurrentNode->Key[Index] = Successor->Key[0];
if(True == SubNode->IsLeaf){
SubNode->Key[SubNode->Num - 1] = CurrentNode->Key[Index];
}
BpDelete(T, Successor, Successor->Key[0]);
}
else{
BpMerge(T, CurrentNode, Index, Index + 1);
BpDelete(T, Precursor, Val);
}
}
}
else{
if(True == CurrentNode->IsLeaf){
return;
}
else{
if(Index > 0){
Precursor = CurrentNode->Child[Index - 1];
}
SubNode = CurrentNode->Child[Index];
if(Index < CurrentNode->Num){
Successor = CurrentNode->Child[Index + 1];
}
if(SubNode->Num >= MinDegree){
BpDelete(T, SubNode, Val);
}
else{
if(Index > 0 && Precursor->Num >= MinDegree){
ShiftKey(SubNode->Key, True, 0, SubNode->Num - 1);
SubNode->Key[0] = CurrentNode->Key[Index - 1];
if(True == SubNode->IsLeaf){
CurrentNode->Key[Index - 1] = Precursor->Key[Precursor->Num - 2];
}
else{
CurrentNode->Key[Index - 1] = Precursor->Key[Precursor->Num - 1];
ShiftChild(SubNode->Child, True, 0, SubNode->Num);
SubNode->Child[0] = Precursor->Child[Precursor->Num];
}
(SubNode->Num)++;
(Precursor->Num)--;
BpDelete(T, SubNode, Val);
}
else if(Index < CurrentNode->Num && Successor->Num >= MinDegree){
if(True == SubNode->IsLeaf){
SubNode->Key[SubNode->Num] = Successor->Key[0];
}
else{
SubNode->Key[SubNode->Num] = CurrentNode->Key[Index];
}
CurrentNode->Key[Index] = Successor->Key[0];
SubNode->Child[SubNode->Num + 1] = Successor->Child[0];
(SubNode->Num)++;
ShiftKey(Successor->Key, False, 1, Successor->Num - 1);
ShiftChild(Successor->Child, False, 1, Successor->Num);
(Successor->Num)--;
BpDelete(T, SubNode, Val);
}
else{
if(Index > 0){
BpMerge(T, CurrentNode, Index - 1, Index);
BpDelete(T, Precursor, Val);
}
else{
BpMerge(T, CurrentNode, Index, Index + 1);
BpDelete(T, SubNode, Val);
}
}
}
}
}
}
void BpMerge(PtrBp T, PtrBpNode CurrentNode, int LeftIndex, int RightIndex){
int i;
PtrBpNode LeftNode = CurrentNode->Child[LeftIndex];
PtrBpNode RightNode = CurrentNode->Child[RightIndex];
if(True == LeftNode->IsLeaf){
for(i = 0; i < MinDegree - 1; i++){
LeftNode->Key[i + MinDegree - 1] = RightNode->Key[i];
}
LeftNode->Num = MinDegree * 2 - 2;
LeftNode->Next = RightNode->Next;
}
else{
for(i = 0; i < MinDegree - 1; i++){
LeftNode->Key[i + MinDegree] = RightNode->Key[i];
}
for(i = 0; i < MinDegree; i++){
LeftNode->Key[i + MinDegree] = RightNode->Key[i];
}
LeftNode->Key[MinDegree - 1] = CurrentNode->Key[LeftIndex];
LeftNode->Num = MinDegree * 2 - 1;
}
ShiftKey(CurrentNode->Key, False, LeftIndex + 1, CurrentNode->Num - 1);
ShiftChild(CurrentNode->Child, False, RightIndex + 1, CurrentNode->Num);
(CurrentNode->Num)--;
if(CurrentNode == T->Root && 0 == CurrentNode->Num){
T->Root = LeftNode;
}
}
void BpPrintTree(PtrBpNode Root){
int i;
if(NULL == Root){
return;
}
putchar('[');
for(i = 0; i < Root->Num; i++){
printf("%d", Root->Key[i]);
if(i != Root->Num - 1){
putchar(' ');
}
}
putchar(']');
printf("%d ", Root->IsLeaf);
printf("%d", Root->Num);
putchar('\n');
for(i = 0; i <= Root->Num; i++){
BpPrintTree(Root->Child[i]);
}
}
void BpCreateTree(PtrBp T){
int i;
int a[] = {12,1,9,2,0,11,7,19,4,15,18,5,14,13,10,16,6,3,8,17,20,21,23};
for(i = 0; i < 23; i++){
BpInsert(T, a[i]);
BpPrintTree(T->Root);
printf("The End\n");
}
}
B+树的插入、删除(附源代码)的更多相关文章
- AVL树的插入删除查找算法实现和分析-1
至于什么是AVL树和AVL树的一些概念问题在这里就不多说了,下面是我写的代码,里面的注释非常详细地说明了实现的思想和方法. 因为在操作时真正需要的是子树高度的差,所以这里采用-1,0,1来表示左子树和 ...
- 数据结构系列之2-3-4树的插入、查找、删除和遍历完整版源代码实现与分析(dart语言实现)
本文属于原创,转载请注明来源. 在上一篇博文中,详细介绍了2-3树的操作(具体地址:https://www.cnblogs.com/outerspace/p/10861488.html),那么对于更多 ...
- AVL树的插入和删除
一.AVL 树 在计算机科学中,AVL树是最早被发明的自平衡二叉查找树.在AVL树中,任一节点对应的两棵子树的最大高度差为 1,因此它也被称为高度平衡树.查找.插入和删除在平均和最坏情况下的时间复杂度 ...
- B树和B+树的插入、删除图文详解
简介:本文主要介绍了B树和B+树的插入.删除操作.写这篇博客的目的是发现没有相关博客以举例的方式详细介绍B+树的相关操作,由于自身对某些细节也感到很迷惑,通过查阅相关资料,对B+树的操作有所顿悟,写下 ...
- B树和B+树的插入、删除图文详解(good)
B树和B+树的插入.删除图文详解 1. B树 1. B树的定义 B树也称B-树,它是一颗多路平衡查找树.我们描述一颗B树时需要指定它的阶数,阶数表示了一个结点最多有多少个孩子结点,一般用字母m表示阶数 ...
- python Trie树和双数组TRIE树的实现. 拥有3个功能:插入,删除,给前缀智能找到所有能匹配的单词
#coding=utf- #字典嵌套牛逼,别人写的,这样每一层非常多的东西,搜索就快了,树高26.所以整体搜索一个不关多大的单词表 #还是O(). ''' Python 字典 setdefault() ...
- AVL 树的插入、删除、旋转归纳
参考链接: http://blog.csdn.net/gabriel1026/article/details/6311339 1126号注:先前有一个概念搞混了: 节点的深度 Depth 是指从根 ...
- MySQL B+树 的插入与删除
一.MySQL Index 的插入 有如下B+树,其高度为2,每页可存放4条记录,扇出为5.所有记录都在叶子节点上, 并且是顺序存放,如果用户从最左边的叶子节点开始顺序遍历,可以得到所有简直的顺序 排 ...
- 数据结构系列之2-3树的插入、查找、删除和遍历完整版代码实现(dart语言实现)
弄懂了二叉树以后,再来看2-3树.网上.书上看了一堆文章和讲解,大部分是概念,很少有代码实现,尤其是删除操作的代码实现.当然,因为2-3树的特性,插入和删除都是比较复杂的,因此经过思考,独创了删除时分 ...
随机推荐
- [数据结构]Treap简介
[写在前面的话] 如果想学Treap,请先了解BST和BST的旋转 二叉搜索树(BST)(百度百科):[here] 英文好的读者可以戳这里(维基百科) 自己的博客:关于旋转(很水,顶多就算是了解怎么旋 ...
- javascript svg 页面 loading
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 屌爆了的两个在线编辑网站runjs和jsbin
作者:zccst HTML5+css3做的小游戏 http://timelineapp.pointstone.org/coreball/game.html 切图工具:http://kuaiqie.co ...
- Myeclipse创建新项目
1. 打开myeclipse, 配置mysql server preference里找到 show view-- DB Browser, 新建数据库驱动. 1. URL填写: jdbc:mysql:/ ...
- openstack controller ha测试环境搭建记录(五)——配置rabbitmq集群
配置rabbitmq集群的步骤非常简单,因为其本身含集群功能,参考openstack官网文档:http://docs.openstack.org/ha-guide/controller-ha-rabb ...
- ubuntu php 出现 Cannot find module (SNMPv2-TC) 等错误
有时编译一个东西或输入某个命令的时候会出现: Cannot find module (MTA-MIB): At line in (none) Cannot find module (NETWORK-S ...
- mysql show命令
MySQL中有很多的基本命令,show命令也是其中之一,在很多使用者中对show命令的使用还容易产生混淆,本文汇集了show命令的众多用法. 1. show tables或show tables fr ...
- VS2010打开旧版本MFC工程无对话框
解决方案: 左侧有个"资源视图",打开,里面就能找得到对话框,如果没有资源视图,就在菜单的视图选项里打开资源视图!
- iOS开发之圆角指定 分类: ios技术 2015-05-25 16:26 191人阅读 评论(0) 收藏
如果需要将UIView的4个角全部都为圆角,做法相当简单,只需设置其Layer的cornerRadius属性即可(项目需要使用QuartzCore框架).而若要指定某几个角(小于4)为圆角而别的不变时 ...
- Góra urządzenia z dwoma zwiększyć moc może sprawić
Zaprojektowany z rzeczywistym komfortu i łatwości od sportowca w swoim umyśle, kolejna edycja ze wzr ...