1、B+树的代码实现B+树的实现。这个B+树是建立在操作系统的文件系统之上的,并没有自己的文件系统。B+树的节点全部存储在一个文件中。由于每个节点的大小是相同的,所以我对每个节点 进行编号,即每个节点的id。这样每个节点在文件的字节位置就可以通过计算sizeof(BPNode)*(c-id - 1)得到。 所以,每个B+树的节点有一个id属性,就是记录自己的标号。 同时对B+树建立一个结构体,这个结构体中的root属性,用于指向读入内存后的树的根节点。 locate属性记录树的根节点的在文件中的标号。num属性记录这棵树的节点个数,每次新增一个节点都会加一。 name属性记录用于存储这个B+树的文
2、件名(相对cpp文件所在的文件夹),fp属性用于记录打开这个文件时的文件指针 因为这个文件只记录B+树的节点,所以每次插入的时候只需要直接插入最后(只有num 个节点,同时新插入的节点的id是num+1) 暂时不考虑删除节点的文件空间回收。 打开文件是要注意打开模式,r+模式可以才可以随意用fseek()定位之后,读或写。 fseek()和fread()和fwrite()是用于二进制打开的文件,如果文本模式打开,可能出现问题,如:覆盖。 #include #include #include #include #define T 3 /b+树的度数 #define KeyType int #de
3、fine Pointer int /节点结构体 typedef struct BPNode unsigned int id;/记录这个节点在文件的中的编号 unsigned int n; /记录这个节点有多少个关键字 int leaf; /判断是否为页节点 KeyType key2*T;/关键字(及对应每个孩子节点的中关键字最小的关键字) Pointer child2*T;/指针,记录每个孩子在文件的第几个位置 Pointer next;/指针,记录下一个兄弟 BPNode,*P_BPNode; /树的结构体 typedef struct BPTree P_BPNode root; unsig
4、ned int locate;/记录根节点的在文件中的标号,即id unsigned int num; /记录更有多少个节点 char name100; /用于存储B+树的节点文件的名字 FILE *fp; /打开写入name文件时,使用 int start; /最小的数据所在的叶节点 BPTree,*P_BPTree; BPTree indexBPTree; /全局变量,b+树 int writeNode(P_BPNode w) fseek(indexBPTree.fp, sizeof(BPNode)*(w-id - 1) + 2*sizeof(int), SEEK_SET); fwrite
5、(w, sizeof(BPNode),1,indexBPTree.fp); return 0; int readNode(P_BPNode r, Pointer id) fseek(indexBPTree.fp, (sizeof(BPNode)*(id - 1) + 2*sizeof(int), SEEK_SET); fread(r, (sizeof(BPNode),1,indexBPTree.fp); return 0; int pNode(P_BPNode n); int createIndexBPTree (char *tableName, char *attr) /创建B+树,并进行相
6、应的初始化,B+树的结构体是一个全局变量。 P_BPNode root; indexBPTree.root = (P_BPNode)malloc(sizeof(BPNode); indexBPTree.num = 1; indexBPTree.start = 1; memcpy(indexBPTree.name, .table, sizeof(.table); strcat(indexBPTree.name, tableName); strcat(indexBPTree.name, .); strcat(indexBPTree.name, attr); puts(indexBPTree.nam
7、e); root = indexBPTree.root; root-n = 0; root-leaf = 1; root-next = -1; root-id = 1; indexBPTree.locate = 1; indexBPTree.fp = fopen(indexBPTree.name, wb); fwrite(&indexBPTree.num, sizeof(int),1,indexBPTree.fp); fwrite(&indexBPTree.locate, sizeof(int),1,indexBPTree.fp); writeNode(root); fclose(indexB
8、PTree.fp); /* printf(原始:%dn, indexBPTree.root-next); memset(indexBPTree.root,0,sizeof(BPNode); printf(memset后:%dn, indexBPTree.root-next); indexBPTree.fp = fopen(indexBPTree.name,r); fread(indexBPTree.root, sizeof(BPNode),1,indexBPTree.fp); fclose(indexBPTree.fp); printf(读取文件后:%dn, indexBPTree.root-
9、next); */ free(root); indexBPTree.root = NULL; return 0; int splitBPNode (P_BPNode p, P_BPNode c, int i) /节点的分裂,要求p节点至少还能插入一个节点,c节点是满的,即n为2*T; int j; P_BPNode b; b = (P_BPNode)malloc(sizeof(BPNode); b-leaf = c-leaf; b-n = T; b-id = indexBPTree.num+1; /为b赋值id号,用于表示该节点,同时id号就是这个节点在文件的位置 b-next = c-nex
10、t; /为b的next赋值,即原来的c节点的next /将c节点的后半部分关键字复制给b for (j = 0; j keyj = c-keyj+T; b-childj = c-childj+T; /至此b节点的对应元素已经建立好了,但还需要写入文件 indexBPTree.num+; c-n = T; /c节点的关键字数目减半 c-next = b-id; /将p节点的i之后的节点后移 for (j = p-n - 1; j i; j-) p-keyj+1 = p-keyj; p-childj+1 = p-childj; /将b节点插入p中 p-keyi+1 = b-key0; p-chil
11、di+1 = b-id; p-n+; /p关键字个数加一 /写入p writeNode(p); writeNode(c); writeNode(b); free(b); return 0; /splitBPNode int insertBPNodeNotFull(P_BPNode s, KeyType k, unsigned int id) /插入,要求s节点不是满的 int i = s-n-1; if (s-leaf) /叶节点,找的合适的位置 while (i = 0 & s-keyi k) s-keyi+1 = s-keyi; s-childi+1 = s-childi; i-; s-k
12、eyi+1 = k; s-childi+1 = id; s-n+; writeNode(s); else P_BPNode tmp = (P_BPNode)malloc(sizeof(BPNode); while (i = 0 & s-keyi k) i-; if (i keyi = k; writeNode(s); readNode(tmp, s-childi); /读取对应的 if (tmp-n = 2*T) splitBPNode(s, tmp, i); if (k s-keyi+1) i+; readNode(tmp, s-childi); /重新读取,有待优化 insertBPNod
13、eNotFull(tmp, k, id); free(tmp); return 0; Pointer equalSearch(P_BPTree tree, KeyType k) /等值查询,给出key值,查找对应的id,并返回。如果不存在该节点,返回一个负数int i; int result; P_BPNode r; r = tree-root; if (k key0) /比最小的节点小 return -1; P_BPNode tmp = (P_BPNode)malloc(sizeof(BPNode); while (1) i = r-n - 1; while (i = 0 & r-keyi
14、k) i-; if (r-leaf) /是叶子,结束 break; readNode(tmp, r-childi); r = tmp; /while if (r-keyi childi; free(tmp); tmp = NULL; return result; /equalSearch int rangeSearch (P_BPTree tree, KeyType low, KeyType high) /范围查找,key值大于等于low,小于等于high。返回范围内的个数, unsigned int i; P_BPNode r = tree-root; Pointer *result; P_
15、BPNode tmp = (P_BPNode)malloc(sizeof(BPNode); if (high low) /low = high才有能有结果 return 0; if (high key0) return 0; if (low key0) low = r-key0; while (1) i = r-n - 1; while (i = 0 & r-keyi low) i-; if (r-leaf) /是叶子,结束 break; readNode(tmp, r-childi); r = tmp; /while if (r-keyi low) i+; unsigned int num=
16、100; result = (Pointer *)malloc(sizeof(Pointer)*num); unsigned int j = 0; while (1) for (; i n & r-keyi = num) num += 100; realloc(result, sizeof(Pointer)*num); resultj+ = r-childi; / printf(sid:%d iid: %d id:%dn, r-keyi,r-id, r-childi); if (i n | r-next next); r = tmp; i = 0; /while free(tmp); tmp
17、= NULL; return j; /rangeSearch int insertKeyInBPTree (P_BPTree tree, KeyType k, Pointer id) /向树中插入节点 P_BPNode r = tree-root; if (equalSearch(tree, k) 0) printf(元素已存在!); return -1; if (tree-root-n = 2*T) /根节点满了,重新分配根节点,并进行初始化 P_BPNode s = (P_BPNode)malloc(sizeof(BPNode); s-leaf = 0; s-n = 1; s-key0 =
18、 r-key0; s-child0 = r-id; s-id = tree-num + 1; s-next = -1; /将新的根写入磁盘 writeNode(s); tree-num+; writeNode(r); splitBPNode (s, r, 0); /根变为s,所以将新根copy到tree-root指针所指向的内存。(tree-root将一直指向一片开辟了的内存,且时刻保存树根的整个节点) memcpy(tree-root, s, sizeof(BPNode); tree-locate = s-id; insertBPNodeNotFull(s, k, id); free(s);
19、 /释放内存 else insertBPNodeNotFull(r, k, id); return 0; /insertBPNode int initIndexBPTree(char *tableName, char *attr) /初始化BPTree,打开相应文件,fp记录;为root分配内存可以存储一个节点的内存,并读入根节点 indexBPTree.root = (P_BPNode)malloc(sizeof(BPNode); indexBPTree.start = 1; memcpy(indexBPTree.name, .table, sizeof(.table); strcat(in
20、dexBPTree.name, tableName); strcat(indexBPTree.name, .); strcat(indexBPTree.name, attr); indexBPTree.fp = fopen(indexBPTree.name, rb+); fread(&indexBPTree.num,sizeof(int),1, indexBPTree.fp); fread(&indexBPTree.locate,sizeof(int),1,indexBPTree.fp); readNode(indexBPTree.root, indexBPTree.locate); retu
21、rn 0; int endBPTree() /将建立的树结束 fseek(indexBPTree.fp, 0, SEEK_SET); fwrite(&indexBPTree.num, sizeof(int),1,indexBPTree.fp); fwrite(&indexBPTree.locate, sizeof(int),1,indexBPTree.fp); free(indexBPTree.root); fclose(indexBPTree.fp); return 0; int pNode(P_BPNode n) /输出节点 printf(%s id:%d next:%d 个数:%dn ,
22、n-leaf?是叶节点:不是叶节点, n-id, n-next, n-n); for(unsigned int i = 0; i n; i+) printf( key%d:%dt,i,n-keyi); puts(); for(i = 0; i n; i+) printf(child%d:%dt,i,n-childi); puts(); return 0; /pNode int replaceKeyInBPTree(P_BPTree tree, KeyType oldkey, KeyType newkey) /将oldkey替换为newkey P_BPNode r = tree-root; in
23、t i; P_BPNode tmp = (P_BPNode)malloc(sizeof(BPNode); while (1) i = r-n - 1; while (i = 0 & r-keyi oldkey) i-; if (r-keyi = oldkey) r-keyi = newkey; writeNode(r); if (r-leaf) break; readNode(tmp, r-childi); r = tmp; free(tmp); return 0; int adjustToDel(P_BPNode p, P_BPNode x, unsigned int i) /p指向x的父节
24、点,i指的是,x是p的下标 unsigned int j; P_BPNode left = NULL; P_BPNode right = NULL; P_BPNode tmp = (P_BPNode)malloc(sizeof(BPNode); if (i 0 ) /x有左兄弟 readNode(tmp, p-childi-1); left = tmp; if (left-n T) for (j = x-n; j 0; j-) x-keyj = x-keyj-1; x-childj = x-childj-1; x-n+; x-key0 = left-keyleft-n-1; x-child0
25、= left-childleft-n-1; writeNode(x); left-n-; writeNode(left); p-keyi = x-key0; writeNode(p); return 0; /if if (i n - 1) /x有又兄弟 readNode(tmp, p-childi+1); right = tmp; left = NULL; if (right-n T) x-keyx-n = right-key0; x-childx-n = right-child0; x-n+; writeNode(x); for (j = 0; j n-1; j+) right-keyj =
26、 right-keyj+1; right-childj = right-childj+1; right-n-; writeNode(right); p-keyi+1 = right-key0; writeNode(p); return 0; if (left = tmp) for (j = 0; j keyT+j = x-keyj; left-childT+j = x-childj; left-n += T; left-next = x-next; writeNode(left); for (j = i; j n - 1; j+) p-keyj = p-keyj+1; p-childj = p
27、-childj+1; p-n-; writeNode(p); memcpy(x, left, sizeof(BPNode); else for (j = 0; j keyT+j = right-keyj; x-childT+j = right-childj; x-n += T; x-next = right-next; writeNode(x); for (j = i+1; j n -1; j+) p-keyj = p-keyj+1; p-childj = p-childj+1; p-n-; writeNode(p); free(tmp); left = right = tmp = NULL; return 0; /调用这个函数是,参数节点p,必须满足相应的要求: /如果p是根节点且是叶子节点,则没有要求 /如果p是根节点(非叶),则p节点的子节点个数不小于2(B+树