昨天研究后缀数组和后缀树,发现将后缀树的建立第一个拉低到接近线性时间的Edward McCreigh竟然就是B-Tree的发明者之一。
B-Tree的另一个发明者bayer居然还是红黑树的发明者,简直是树精。
想想虽然B-Tree的原理是了解的,但是还从来没有自己写过B树的实现。
diors的星期天晚上是如此的寂寞空虚,实在找不到事情可以做,试着写写看。
/*************************************************************
* file:btree_operation.c
* brief:operations of b_tree(included build/search/insert/delete)
* yejing@2015.1.25 1.0 create
*************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/*2,3,4树*/
#define btree_dg 2
#define CHILD_NUM 2 * btree_dg
#define KEY_NUM 2 * btree_dg - 1
typedef struct _btree_t{
int key_count;
int key[KEY_NUM];
struct _btree_t* child[CHILD_NUM];
int is_leaf;
}btree_t;
static btree_t* allocate_btree_node(void){
btree_t* node = (btree_t*)malloc(sizeof(btree_t));
if(!node)
assert(0);
memset((char*)node, 0, sizeof(btree_t));
return node;
}
btree_t* build_a_btree(void){
btree_t* root = allocate_btree_node();
if(!root)
assert(0);
root->is_leaf = 1;
return root;
}
btree_t* btree_search(btree_t* root, int key){
int i = 0;
while(i < root->key_count && key > root->key[i])
++i
if(i < root->key_count && key = root->key[i])
return root;
if(root->is_leaf)
return NULL;
else
return btree_search(root->child[i], key);
}
/*
child是一个满节点,它是其父亲father的第child_index+1个孩子。
btree_split_child将child按其中间关键字分裂成两个btree_dg-1的子树。
同时将其中间关键字上浮到father中。
此函数从根节点由上向下调用,所以father肯定不会是满的。
*/
void btree_split_child(btree_t* father, btree_t* child, int child_index){
if(!father || !child || child_index < 0 || child_index + 1 > CHILD_NUM)
assert(0);
int i = 0;
//新建一个tmp节点,用于收养child中较大的一半子女
btree_t* tmp = allocate_btree_node();
if(!tmp)
assert(0);
//如果child是叶节点,tmp也应该是叶节点
tmp->is_leaf = child->is_leaf;
//调整tmp和child的关键字计数
tmp->key_count = btree_dg - 1;
child->key_count = btree_dg - 1;
//将child后面一半较大的关键字赋给tmp
for(i = 0; i < btree_dg - 1; ++i)
tmp->key[i] = child[btree_dg + i];
//如果child不是叶节点,tmp将收养其后半部分孩子
if(!child->is_leaf)
for(i = 0; i < btree_dg; ++i)
tmp->child[i] = child[btree_dg + i];
//调整father的child指针数组位置,给tmp留出空间,并将tmp托管给father
for(i = father->key_count; i > index; --i)
father->child[i + 1] = father->child[i];
father->child[index + 1] = tmp;
//将child的中间关键值上浮给father
for(i = father->key_count - 1; i > index - 1; --i)
father->key[i + 1] = father->key[i];
father->key[index] = child->[btree_dg - 1];
//最后修改father的keycount
father->key_count++;
return;
}
/*
将key插入到node中,基于node不是满的。
在需要时会沿着树向下递归,必要的时候调用btree_split_child分割节点
*/
void btree_insert_nonfull(btree_t* node, int key){
if(!node)
assert(0);
}
btree_t* btree_insert(btree_t* root, int key){
if(!root)
assert(0);
btree_t* tmp = root;
//节点满
if(tmp->key_count == KEY_NUM){
btree_t* tmp1 = allocate_btree_node();
if(!tmp1)
assert(0);
root = tmp1;
tmp1->is_leaf = 0;
tmp1->key_count = 0;
tmp1->child[0] = tmp;
btree_split_child(tmp1, 0, root);
btree_insert_nonfull(tmp1, key);
}
else{
btree_insert_nonfull(tmp, key)
}
}