# include <stdio.h> # include <stdlib.h> # include "btrees.h" /* 给一个结点分配空间 */ struct btnode * allocateNode(struct btnode *ptr){ int i,max; ptr = (struct btnode *)malloc(sizeof(struct btnode)); if(!ptr){ printf("allocated error!\n"); exit(1); } max = 2*M; for(i=0; i<max; i++) ptr->p[i] = NULL; /* 初始化指针 */ memset(ptr->k, 0, (max-1)*sizeof(int)); /* 初始化键的值*/ return ptr; } /* 创建一个空的B树,就一个根结点 */ struct btnode * btreeCreate(struct btnode *root){ root = allocateNode(root); root->keyNum = 0; root->isleaf = 1; return root; } /*函数目的:在B树中递归的搜索给定的数据,如果存在则返回数据所在节点和在节点中 * 的位置,不存在返回NULL */ /* struct searchResult * btreeSearch(struct btree *root, int data){ int i=0; struct searchResult result; //找到节点中数据所在位置 while((i<(2*M-1)) && (data>root->k[i])) i++; //数据找到,返回结果 if(root->k[i] == data){ result.ptr = root; result.pos = i; return result; } //已经搜索到叶节点,数据不存在,返回NULL if(root->isleaf){ result.ptr = NULL; result.pos = -1; return result; } else{ //非叶节点,继续搜索子树节点 return btreeSearch(root->p[i], data); } } */ //函数目的:分裂存储数达到最大的节点 void btreeSplitChild(struct btnode *parent, int pos, struct btnode *child){ struct btnode *child2; int i; //为新分裂出的节点分配空间 child2 = allocateNode(child2); //与被分裂点同级 child2->isleaf = child->isleaf; //设置节点数 child2->keyNum = M-1; //复制数据 for(i=0; i<M-1; i++) child2->k[i] = child->k[i+M]; //如果不是叶节点,复制指针 if(!child->isleaf) for(i=0; i<M; i++) child2->p[i] = child->p[i+M]; child->keyNum = M-1; //将中间数作为索引插入到双亲节点中 //插入点后面的关键字和指针都往后移动一个位置 for(i=parent->keyNum; i>pos; i--){ parent->k[i] = parent->k[i-1]; parent->p[i+1] = parent->p[i]; } parent->k[pos] = child->k[M-1]; parent->keyNum++; parent->p[pos+1] = child2; } /* 函数目的:向非满的节点中插入一个数据 * 注意:插入前保证key在原来的B树中不存在 */ void btreeInsertNoneFull(struct btnode *ptr, int data){ int i; struct btnode *child; //要插入结点的子结点 i = ptr->keyNum; //如果是叶节点,直接插入数据 if(ptr->isleaf){ while((i>0) && (data<ptr->k[i-1])){ ptr->k[i] = ptr->k[i-1]; i--; } //插入数据 ptr->k[i] = data; ptr->keyNum++; } else{ //不是叶节点,找到数据应插入的子节点并插入 while((i>0) && (data<ptr->k[i-1])) i--; child = ptr->p[i]; if(child->keyNum == 2*M-1){ btreeSplitChild(ptr, i, child); if(data > ptr->k[i]) i++; } child = ptr->p[i]; btreeInsertNoneFull(child, data); //在子树中递归 } } /* 插入一个结点 */ struct btnode * btreeInsert(struct btnode *root, int data){ struct btnode *new; /* 检查是否根节点已满,如果已满,分裂并生成新的根节点 */ if(root->keyNum == 2*M-1){ new = allocateNode(new); new->isleaf = 0; new->keyNum = 0; new->p[0] = root; btreeSplitChild(new, 0, root); btreeInsertNoneFull(new, data); return new; } else{ //还没到最大数据数,直接插入 btreeInsertNoneFull(root, data); return root; } } //函数目的:广度优先显示树 void btreeDisplay(struct btnode *root){ int i, queueNum=0; int j; struct btnode *queue[20]; struct btnode *current; //加入队列 queue[queueNum] = root; queueNum++; while(queueNum>0){ //出队 current = queue[0]; queueNum--; //移出第一个元素后后面的元素往前移动一个位置 for(i=0; i<queueNum; i++) queue[i] = queue[i+1]; //显示节点 j = current->keyNum; printf("[ "); for(i=0; i<j; i++){ printf("%d ", current->k[i]); } printf("] "); //子节点入队 if(current!=NULL && current->isleaf!=1){ for(i=0; i<=(current->keyNum); i++){ queue[queueNum] = current->p[i]; queueNum++; } } } printf("\n"); } int main() { struct btnode *root; int a[13] = {18, 31, 12, 10, 15, 48, 45, 47, 50, 52, 23, 30, 20}; int i; root = btreeCreate(root); for(i=0; i<13; i++){ root = btreeInsert(root, a[i]); btreeDisplay(root); } return 0; }