B+tree详解及实现(C语言)

来源:互联网 发布:php api接口开发 编辑:程序博客网 时间:2024/06/09 14:01
1 什么是B+tree
如果你还不了解B-tree,那么请自行了解。可以参考我的这篇帖子---B-tree详解及实现。
B+tree是B-tree的一个变种:在B-tree的基础上,为叶子节点增加链表指针,而且所有的关键字都在叶子节点中出现,且数据只存储在叶子节点中。非叶子节点的关键字仅作为叶子节点的索引。下图是一棵B+tree。

B+tree 的插入和删除基本和B-tree一样,只是多了数据结构多了next字段,所以要注意。

2. B+tree的实现
2.1 头文件
////  BPlusTree.h//  BPlusTree////  Created by Wuyixin on 2017/8/4.//  Copyright © 2017年 Coding365. All rights reserved.//#ifndef BPlusTree_h#define BPlusTree_h#include <stdio.h>#include <stdlib.h>#include <limits.h>#define M (4)#define LIMIT_M_2 (M % 2 ? (M + 1)/2 : M/2)typedef struct BPlusNode *BPlusTree,*Position;typedef int KeyType;struct BPlusNode{    int KeyNum;    KeyType Key[M + 1];    BPlusTree Children[M + 1];    BPlusTree Next;};/* 初始化 */extern BPlusTree Initialize();/* 插入 */extern BPlusTree Insert(BPlusTree T,KeyType Key);/* 删除 */extern BPlusTree Remove(BPlusTree T,KeyType Key);/* 销毁 */extern BPlusTree Destroy(BPlusTree T);/* 遍历节点 */extern void Travel(BPlusTree T);/* 遍历树叶节点的数据 */extern void TravelData(BPlusTree T);#endif /* BPlusTree_h */



2.2 实现文件
////  BPlusTree.c//  BPlusTree////  Created by Wuyixin on 2017/8/4.//  Copyright © 2017年 Coding365. All rights reserved.//#include "BPlusTree.h"static KeyType Unavailable = INT_MIN;/* 生成节点并初始化 */static BPlusTree MallocNewNode(){    BPlusTree NewNode;    int i;    NewNode = malloc(sizeof(struct BPlusNode));    if (NewNode == NULL)        exit(EXIT_FAILURE);            i = 0;    while (i < M + 1){        NewNode->Key[i] = Unavailable;        NewNode->Children[i] = NULL;        i++;    }    NewNode->Next = NULL;    NewNode->KeyNum = 0;        return NewNode;}/* 初始化 */extern BPlusTree Initialize(){        BPlusTree T;        if (M < (3)){        printf("M最小等于3!");        exit(EXIT_FAILURE);            }    /* 根结点 */    T = MallocNewNode();        return T;}static Position FindMostLeft(Position P){    Position Tmp;        Tmp = P;        while (Tmp != NULL && Tmp->Children[0] != NULL) {        Tmp = Tmp->Children[0];    }    return Tmp;}static Position FindMostRight(Position P){    Position Tmp;        Tmp = P;        while (Tmp != NULL && Tmp->Children[Tmp->KeyNum - 1] != NULL) {        Tmp = Tmp->Children[Tmp->KeyNum - 1];    }    return Tmp;}/* 寻找一个兄弟节点,其存储的关键字未满,否则返回NULL */static Position FindSibling(Position Parent,int i){    Position Sibling;    int Limit;        Limit = M;        Sibling = NULL;    if (i == 0){        if (Parent->Children[1]->KeyNum < Limit)            Sibling = Parent->Children[1];    }    else if (Parent->Children[i - 1]->KeyNum < Limit)        Sibling = Parent->Children[i - 1];    else if (i + 1 < Parent->KeyNum && Parent->Children[i + 1]->KeyNum < Limit){        Sibling = Parent->Children[i + 1];    }        return Sibling;}/* 查找兄弟节点,其关键字数大于M/2 ;没有返回NULL*/static Position FindSiblingKeyNum_M_2(Position Parent,int i,int *j){    int Limit;    Position Sibling;    Sibling = NULL;        Limit = LIMIT_M_2;        if (i == 0){        if (Parent->Children[1]->KeyNum > Limit){            Sibling = Parent->Children[1];            *j = 1;        }    }    else{        if (Parent->Children[i - 1]->KeyNum > Limit){            Sibling = Parent->Children[i - 1];            *j = i - 1;        }        else if (i + 1 < Parent->KeyNum && Parent->Children[i + 1]->KeyNum > Limit){            Sibling = Parent->Children[i + 1];            *j = i + 1;        }            }        return Sibling;}/* 当要对X插入Key的时候,i是X在Parent的位置,j是Key要插入的位置   当要对Parent插入X节点的时候,i是要插入的位置,Key和j的值没有用 */static Position InsertElement(int isKey, Position Parent,Position X,KeyType Key,int i,int j){        int k;    if (isKey){        /* 插入key */        k = X->KeyNum - 1;        while (k >= j){            X->Key[k + 1] = X->Key[k];k--;        }                X->Key[j] = Key;                if (Parent != NULL)            Parent->Key[i] = X->Key[0];                X->KeyNum++;            }else{        /* 插入节点 */                /* 对树叶节点进行连接 */        if (X->Children[0] == NULL){            if (i > 0)                Parent->Children[i - 1]->Next = X;            X->Next = Parent->Children[i];        }                k = Parent->KeyNum - 1;        while (k >= i){            Parent->Children[k + 1] = Parent->Children[k];            Parent->Key[k + 1] = Parent->Key[k];            k--;        }        Parent->Key[i] = X->Key[0];        Parent->Children[i] = X;                Parent->KeyNum++;            }    return X;}static Position RemoveElement(int isKey, Position Parent,Position X,int i,int j){        int k,Limit;        if (isKey){        Limit = X->KeyNum;        /* 删除key */        k = j + 1;        while (k < Limit){            X->Key[k - 1] = X->Key[k];k++;        }                X->Key[X->KeyNum - 1] = Unavailable;                Parent->Key[i] = X->Key[0];                X->KeyNum--;    }else{        /* 删除节点 */                /* 修改树叶节点的链接 */        if (X->Children[0] == NULL && i > 0){            Parent->Children[i - 1]->Next = Parent->Children[i + 1];        }        Limit = Parent->KeyNum;        k = i + 1;        while (k < Limit){            Parent->Children[k - 1] = Parent->Children[k];            Parent->Key[k - 1] = Parent->Key[k];            k++;        }                Parent->Children[Parent->KeyNum - 1] = NULL;        Parent->Key[Parent->KeyNum - 1] = Unavailable;                Parent->KeyNum--;            }    return X;}/* Src和Dst是两个相邻的节点,i是Src在Parent中的位置; 将Src的元素移动到Dst中 ,n是移动元素的个数*/static Position MoveElement(Position Src,Position Dst,Position Parent,int i,int n){    KeyType TmpKey;    Position Child;    int j,SrcInFront;        SrcInFront = 0;        if (Src->Key[0] < Dst->Key[0])        SrcInFront = 1;        j = 0;    /* 节点Src在Dst前面 */    if (SrcInFront){        if (Src->Children[0] != NULL){            while (j < n) {                Child = Src->Children[Src->KeyNum - 1];                RemoveElement(0, Src, Child, Src->KeyNum - 1, Unavailable);                InsertElement(0, Dst, Child, Unavailable, 0, Unavailable);                j++;            }        }else{            while (j < n) {                TmpKey = Src->Key[Src->KeyNum -1];                RemoveElement(1, Parent, Src, i, Src->KeyNum - 1);                InsertElement(1, Parent, Dst, TmpKey, i + 1, 0);                j++;            }                    }                Parent->Key[i + 1] = Dst->Key[0];        /* 将树叶节点重新连接 */        if (Src->KeyNum > 0)            FindMostRight(Src)->Next = FindMostLeft(Dst);            }else{        if (Src->Children[0] != NULL){            while (j < n) {                Child = Src->Children[0];                RemoveElement(0, Src, Child, 0, Unavailable);                InsertElement(0, Dst, Child, Unavailable, Dst->KeyNum, Unavailable);                j++;            }                    }else{            while (j < n) {                TmpKey = Src->Key[0];                RemoveElement(1, Parent, Src, i, 0);                InsertElement(1, Parent, Dst, TmpKey, i - 1, Dst->KeyNum);                j++;            }                    }                Parent->Key[i] = Src->Key[0];        if (Src->KeyNum > 0)            FindMostRight(Dst)->Next = FindMostLeft(Src);            }        return Parent;}static BPlusTree SplitNode(Position Parent,Position X,int i){    int j,k,Limit;    Position NewNode;        NewNode = MallocNewNode();        k = 0;    j = X->KeyNum / 2;    Limit = X->KeyNum;    while (j < Limit){        if (X->Children[0] != NULL){            NewNode->Children[k] = X->Children[j];            X->Children[j] = NULL;        }        NewNode->Key[k] = X->Key[j];        X->Key[j] = Unavailable;        NewNode->KeyNum++;X->KeyNum--;        j++;k++;    }        if (Parent != NULL)        InsertElement(0, Parent, NewNode, Unavailable, i + 1, Unavailable);    else{        /* 如果是X是根,那么创建新的根并返回 */        Parent = MallocNewNode();        InsertElement(0, Parent, X, Unavailable, 0, Unavailable);        InsertElement(0, Parent, NewNode, Unavailable, 1, Unavailable);                return Parent;    }        return X;}/* 合并节点,X少于M/2关键字,S有大于或等于M/2个关键字*/static Position MergeNode(Position Parent, Position X,Position S,int i){    int Limit;        /* S的关键字数目大于M/2 */    if (S->KeyNum > LIMIT_M_2){        /* 从S中移动一个元素到X中 */        MoveElement(S, X, Parent, i,1);    }else{        /* 将X全部元素移动到S中,并把X删除 */        Limit = X->KeyNum;        MoveElement(X,S, Parent, i,Limit);        RemoveElement(0, Parent, X, i, Unavailable);                free(X);        X = NULL;    }        return Parent;}static BPlusTree RecursiveInsert(BPlusTree T,KeyType Key,int i,BPlusTree Parent){    int j,Limit;    Position Sibling;        /* 查找分支 */    j = 0;    while (j < T->KeyNum && Key >= T->Key[j]){        /* 重复值不插入 */        if (Key == T->Key[j])            return T;        j++;    }    if (j != 0 && T->Children[0] != NULL) j--;        /* 树叶 */    if (T->Children[0] == NULL)        T = InsertElement(1, Parent, T, Key, i, j);    /* 内部节点 */    else        T->Children[j] = RecursiveInsert(T->Children[j], Key, j, T);        /* 调整节点 */        Limit = M;        if (T->KeyNum > Limit){        /* 根 */        if (Parent == NULL){            /* 分裂节点 */            T = SplitNode(Parent, T, i);        }        else{            Sibling = FindSibling(Parent, i);            if (Sibling != NULL){                /* 将T的一个元素(Key或者Child)移动的Sibing中 */                MoveElement(T, Sibling, Parent, i, 1);            }else{                /* 分裂节点 */                T = SplitNode(Parent, T, i);            }        }            }        if (Parent != NULL)        Parent->Key[i] = T->Key[0];            return T;}/* 插入 */extern BPlusTree Insert(BPlusTree T,KeyType Key){    return RecursiveInsert(T, Key, 0, NULL);}static BPlusTree RecursiveRemove(BPlusTree T,KeyType Key,int i,BPlusTree Parent){        int j,NeedAdjust;    Position Sibling,Tmp;        Sibling = NULL;        /* 查找分支 */    j = 0;    while (j < T->KeyNum && Key >= T->Key[j]){        if (Key == T->Key[j])            break;        j++;    }        if (T->Children[0] == NULL){        /* 没找到 */        if (Key != T->Key[j] || j == T->KeyNum)            return T;    }else        if (j == T->KeyNum || Key < T->Key[j]) j--;                /* 树叶 */    if (T->Children[0] == NULL){        T = RemoveElement(1, Parent, T, i, j);    }else{        T->Children[j] = RecursiveRemove(T->Children[j], Key, j, T);    }        NeedAdjust = 0;    /* 树的根或者是一片树叶,或者其儿子数在2到M之间 */    if (Parent == NULL && T->Children[0] != NULL && T->KeyNum < 2)        NeedAdjust = 1;    /* 除根外,所有非树叶节点的儿子数在[M/2]到M之间。(符号[]表示向上取整) */    else if (Parent != NULL && T->Children[0] != NULL && T->KeyNum < LIMIT_M_2)        NeedAdjust = 1;    /* (非根)树叶中关键字的个数也在[M/2]和M之间 */    else if (Parent != NULL && T->Children[0] == NULL && T->KeyNum < LIMIT_M_2)        NeedAdjust = 1;        /* 调整节点 */    if (NeedAdjust){        /* 根 */        if (Parent == NULL){            if(T->Children[0] != NULL && T->KeyNum < 2){                Tmp = T;                T = T->Children[0];                free(Tmp);                return T;            }                    }else{            /* 查找兄弟节点,其关键字数目大于M/2 */            Sibling = FindSiblingKeyNum_M_2(Parent, i,&j);            if (Sibling != NULL){                MoveElement(Sibling, T, Parent, j, 1);            }else{                if (i == 0)                    Sibling = Parent->Children[1];                else                    Sibling = Parent->Children[i - 1];                                Parent = MergeNode(Parent, T, Sibling, i);                T = Parent->Children[i];            }        }            }        return T;}/* 删除 */extern BPlusTree Remove(BPlusTree T,KeyType Key){    return RecursiveRemove(T, Key, 0, NULL);}/* 销毁 */extern BPlusTree Destroy(BPlusTree T){    int i,j;    if (T != NULL){        i = 0;        while (i < T->KeyNum + 1){            Destroy(T->Children[i]);i++;        }                printf("Destroy:(");        j = 0;        while (j < T->KeyNum)/*  T->Key[i] != Unavailable*/            printf("%d:",T->Key[j++]);        printf(") ");        free(T);        T = NULL;    }        return T;}static void RecursiveTravel(BPlusTree T,int Level){    int i;    if (T != NULL){        printf("  ");        printf("[Level:%d]-->",Level);        printf("(");        i = 0;        while (i < T->KeyNum)/*  T->Key[i] != Unavailable*/            printf("%d:",T->Key[i++]);        printf(")");                Level++;                i = 0;        while (i <= T->KeyNum) {            RecursiveTravel(T->Children[i], Level);            i++;        }                    }}/* 遍历 */extern void Travel(BPlusTree T){    RecursiveTravel(T, 0);    printf("\n");}/* 遍历树叶节点的数据 */extern void TravelData(BPlusTree T){    Position Tmp;    int i;    if (T == NULL)        return ;    printf("All Data:");    Tmp = T;    while (Tmp->Children[0] != NULL)        Tmp = Tmp->Children[0];    /* 第一片树叶 */    while (Tmp != NULL){        i = 0;        while (i < Tmp->KeyNum)            printf(" %d",Tmp->Key[i++]);        Tmp = Tmp->Next;    }}



2.3 调用

////  main.c//  BPlusTree////  Created by Wuyixin on 2017/8/4.//  Copyright © 2017年 Coding365. All rights reserved.//#include <stdio.h>#include <time.h>#include "BPlusTree.h"int main(int argc, const char * argv[]) {    int i;    BPlusTree T;    T = Initialize();        clock_t c1 = clock();    i = 10000000;    while (i > 0)        T = Insert(T, i--);    i = 5000001;    while (i < 10000000)        T = Insert(T, i++);        i = 10000000;    while (i > 100)        T = Remove(T, i--);        Travel(T);    Destroy(T);        clock_t c2 = clock();        printf("\n用时: %lu秒\n",(c2 - c1)/CLOCKS_PER_SEC);}



原创粉丝点击