热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

B+树的插入、删除(附源代码)

B+TreeIndexB+树的插入B+树的删除完整测试代码BasicB+树和B树类似(有关B树:http:www.cnblogs.comYu

B+ Tree

Index


  • B+树的插入
  • B+树的删除
  • 完整测试代码

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 if(Key[i] >= Val){
break;
}
}

return i;
}

void BpPrintTree(PtrBpNode Root){
int i;

if(NULL == Root){
return;
}

putchar('[');
for(i = 0; i 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 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 1; i++){
NewNode->Key[i] = SubNode->Key[i + MinDegree];
}
for(i = 0; 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 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] 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 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 1; i++){
NewNode->Key[i] = SubNode->Key[i + MinDegree];
}
for(i = 0; 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+树叶节点的特有性质。

  1. 待删除数据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中的最小数据值代替CurrentNodePrecursor中的Val值,并在Successor中递归删除Val

  • 如果以上均不满足,则合并PrecursorSuccessor,然后在合并后的新节点中递归删除Val

  1. 待删除数据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,同时CurrentNodeKey数组中下标为Index的元素值也由Successor中的最小数据代替,并将SuccessorKey数组的部分元素向左移动一位,相应的Successor中记录数据量的成员Num也应减1,最后在SubNode中递归删除Val

    • 如果以上均不符合,则将SubNodePrecursorSuccessor合并(两者不一定均存在,选择存在的进行合并),然后在合并后的节点中递归删除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 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 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 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 1; i++){
LeftNode->Key[i + MinDegree - 1] = RightNode->Key[i];
}
LeftNode->Num = MinDegree * 2 - 2;
LeftNode->Next = RightNode->Next;
}
else{
for(i = 0; i 1; i++){
LeftNode->Key[i + MinDegree] = RightNode->Key[i];
}
for(i = 0; 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 
#include

#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 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] 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 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 1; i++){
NewNode->Key[i] = SubNode->Key[i + MinDegree];
}
for(i = 0; 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 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 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 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 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 1; i++){
LeftNode->Key[i + MinDegree - 1] = RightNode->Key[i];
}
LeftNode->Num = MinDegree * 2 - 2;
LeftNode->Next = RightNode->Next;
}
else{
for(i = 0; i 1; i++){
LeftNode->Key[i + MinDegree] = RightNode->Key[i];
}
for(i = 0; 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 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");
}
}




推荐阅读
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 成功安装Sabayon Linux在thinkpad X60上的经验分享
    本文分享了作者在国庆期间在thinkpad X60上成功安装Sabayon Linux的经验。通过修改CHOST和执行emerge命令,作者顺利完成了安装过程。Sabayon Linux是一个基于Gentoo Linux的发行版,可以将电脑快速转变为一个功能强大的系统。除了作为一个live DVD使用外,Sabayon Linux还可以被安装在硬盘上,方便用户使用。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 本文为Codeforces 1294A题目的解析,主要讨论了Collecting Coins整除+不整除问题。文章详细介绍了题目的背景和要求,并给出了解题思路和代码实现。同时提供了在线测评地址和相关参考链接。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • LeetCode笔记:剑指Offer 41. 数据流中的中位数(Java、堆、优先队列、知识点)
    本文介绍了LeetCode剑指Offer 41题的解题思路和代码实现,主要涉及了Java中的优先队列和堆排序的知识点。优先队列是Queue接口的实现,可以对其中的元素进行排序,采用小顶堆的方式进行排序。本文还介绍了Java中queue的offer、poll、add、remove、element、peek等方法的区别和用法。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 本文介绍了C函数ispunct()的用法及示例代码。ispunct()函数用于检查传递的字符是否是标点符号,如果是标点符号则返回非零值,否则返回零。示例代码演示了如何使用ispunct()函数来判断字符是否为标点符号。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
author-avatar
batman@zhou
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有