# 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;
}