第18章 B树
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
/*两个约定:(1)B树的根结点始终在主存中,因而无需对根做DISK_READ,
但是根结点被改变后,都需要对根结点做一次DISK_WRITE
(2)任何被当作参数的结点被传递之前,要先对它们做一次DISK_READ*/
#define DISK_READ(x)
#define DISK_WRITE(x)
/*B树的最小度数*/
enum { tree_degree = 3 };
typedef struct tree_type *tree;
struct tree_node {
int num;
void **key;
struct tree_node **child;
bool leaf;
};
struct tree_type {
int (*comp) (const void *, const void *);
struct tree_node *root;
};
void tree_node_ini(struct tree_node *n, int num, bool leaf)
{
n->num = num;
n->leaf = leaf;
int full_key_num = 2 * tree_degree - 1;
int full_child_num = full_key_num + 1;
n->key = malloc(sizeof(void *) * full_key_num);
memset(n->key, 0, sizeof(void *) * full_key_num);
n->child = malloc(sizeof(struct tree_node *) * full_child_num);
memset(n->child, 0, sizeof(struct tree_node *) * (full_child_num));
}
void tree_node_delete_key_child(struct tree_node *x, int key_pos, int child_pos)
{
memmove(&x->key[key_pos], &x->key[key_pos + 1],
sizeof(void *) * (x->num - key_pos - 1));
memmove(&x->child[child_pos], &x->child[child_pos + 1],
sizeof(struct tree_node *) * (x->num - child_pos));
--x->num;
}
void tree_node_insert_key_child(struct tree_node *x, void *key, int key_pos,
struct tree_node *child, int child_pos)
{
memmove(&x->key[key_pos], &x->key[key_pos + 1],
sizeof(void *) * (x->num - key_pos));
x->key[key_pos] = key;
memmove(&x->child[child_pos], &x->child[child_pos + 1],
sizeof(struct tree_node *) * (x->num + 1 - child_pos));
x->child[child_pos] = child;
++x->num;
}
tree tree_create(int (*comp) (const void *, const void *))
{
tree t = malloc(sizeof(struct tree_type));
t->comp = comp;
struct tree_node *x = malloc(sizeof(struct tree_node));
tree_node_ini(x, 0, true);
DISK_WRITE(x);
t->root = x;
return t;
}
void tree_node_destroy(struct tree_node *x)
{
free(x->key);
free(x->child);
free(x);
}
void tree_destroy_all_node(struct tree_node *x, void (*free_key) (void *))
{
if (x == NULL)
return;
for (int i = 0; i < x->num + 1; ++i) {
tree_destroy_all_node(x->child[i], free_key);
}
for (int i = 0; i < x->num; i++) {
free_key(x->key[i]);
}
free(x->key);
free(x->child);
free(x);
}
void tree_destroy(tree t, void (*free_key) (void *))
{
tree_destroy_all_node(t->root, free_key);
free(t);
}
struct tree_node *tree_search(tree t, struct tree_node *x, void *key,
int *index)
{
int i = 0;
while (i < x->num && t->comp(key, x->key[i]) > 0) {
++i;
}
if (i < x->num && t->comp(key, x->key[i]) == 0) {
*index = i;
return x;
}
if (x->leaf) {
return NULL;
} else {
DISK_READ(x->child[i]);
return tree_search(t, x->child[i], key, index);
}
}
//前序遍历
void tree_preorder_walk(struct tree_node *x, int depth,
void (*handle) (const void *))
{
if (x != NULL) {
printf("depth:%d ", depth);
printf("key:(");
for (int i = 0; i < x->num; i++) {
handle(x->key[i]);
if (i < x->num - 1) {
printf(",");
}
}
printf(")\n");
for (int i = 0; i < x->num + 1; ++i) {
tree_preorder_walk(x->child[i], depth + 1, handle);
}
}
}
void tree_split_child(struct tree_node *x, int i, struct tree_node *y)
{
struct tree_node *z = malloc(sizeof(struct tree_node));
tree_node_ini(z, tree_degree - 1, y->leaf);
memcpy(z->key, &y->key[tree_degree],
sizeof(void *) * (tree_degree - 1));
if (!y->leaf) {
memcpy(z->child, &y->child[tree_degree],
sizeof(struct tree_node *) * tree_degree);
}
y->num = tree_degree - 1;
tree_node_insert_key_child(x, y->key[tree_degree - 1], i, z, i + 1);
DISK_WRITE(y);
DISK_WRITE(z);
DISK_WRITE(x);
}
void tree_union_child(tree t, struct tree_node *x, int i, struct tree_node *y,
struct tree_node *z)
{
void *key = x->key[i];
y->key[y->num] = key;
memcpy(&y->key[y->num + 1], z->key, sizeof(void *) * z->num);
memcpy(&y->child[y->num + 1], z->child, sizeof(void *) * (z->num + 1));
y->num += z->num + 1;
tree_node_delete_key_child(x, i, i + 1);
tree_node_destroy(z); //把z释放掉
DISK_WRITE(y);
DISK_WRITE(x);
if (x == t->root && x->num == 0) //如果x是根,并没有元素了
{
t->root = y;
tree_node_destroy(x);
}
}
void tree_insert_not_full(tree t, struct tree_node *x, void *key)
{
int i = x->num - 1;
if (x->leaf) {
while (i >= 0 && t->comp(key, x->key[i]) < 0) {
x->key[i + 1] = x->key[i];
--i;
}
x->key[i + 1] = key;
++x->num;
DISK_WRITE(x);
return;
}
while (i >= 0 && t->comp(key, x->key[i]) < 0) {
--i;
}
++i;
DISK_READ(x->child[i]);
if (x->child[i]->num == 2 * tree_degree - 1) {
tree_split_child(x, i, x->child[i]);
if (t->comp(key, x->key[i]) > 0) {
++i;
}
}
tree_insert_not_full(t, x->child[i], key);
}
void tree_insert(tree t, void *key)
{
struct tree_node *r = t->root;
if (r->num == 2 * tree_degree - 1) {
struct tree_node *s = malloc(sizeof(struct tree_node));
tree_node_ini(s, 0, false);
t->root = s;
s->child[0] = r;
tree_split_child(s, 0, r);
tree_insert_not_full(t, s, key);
} else {
tree_insert_not_full(t, r, key);
}
}
struct tree_node *tree_successor(struct tree_node *x)
{
while (x != NULL && x->child[0] != NULL) {
x = x->child[0];
}
return x;
}
struct tree_node *tree_predecessor(struct tree_node *x)
{
while (x != NULL && x->child[x->num] != NULL) {
x = x->child[x->num];
}
return x;
}
void swap(void *a, void *b, size_t elem_size)
{
if (a == NULL || b == NULL || a == b)
return;
char temp[elem_size]; /*变长数组 */
memcpy(temp, a, elem_size);
memcpy(a, b, elem_size);
memcpy(b, temp, elem_size);
}
struct tree_node *tree_delete(tree t, struct tree_node *x, void *key, int *i);
//情况1,如果关键字k在结点x中而且x是个叶结点
struct tree_node *tree_delete_from_leaf(struct tree_node *x, int *i)
{
void *key = x->key[*i];
tree_node_delete_key_child(x, *i, *i);
x->key[x->num] = key;
*i = x->num; //i保存了删掉的key的位置
return x;
}
//情况2,如果关键字k在结点x中而且x是个内结点
struct tree_node *tree_delete_from_node(tree t, struct tree_node *x, void *key,
int *i)
{
struct tree_node *y = x->child[*i];
//情况2a,结点x中前于k的子结点y包含至少tree_degree个关键字
if (y->num >= tree_degree) {
struct tree_node *predecessor = tree_predecessor(y);
swap(&x->key[*i], &predecessor->key[predecessor->num - 1],
sizeof(void *));
*i = predecessor->num - 1;
return tree_delete_from_leaf(predecessor, i);
}
struct tree_node *z = x->child[*i + 1];
//情况2b,结点x中位于k之后的子结点包含至少tree_degree个关键字
if (z->num >= tree_degree) {
struct tree_node *successor = tree_successor(y);
swap(&x->key[*i], &successor->key[0], sizeof(void *));
*i = 0;
return tree_delete_from_leaf(successor, i);
}
//情况2c,y和z都只有tree_degree-1个关键字
tree_union_child(t, x, *i, y, z);
return tree_delete(t, y, key, i);
}
//如果关键字k不在内结点x中,则确定必包含k的正确的子树的根c
struct tree_node *tree_delete_from_child(tree t, struct tree_node *x, void *key,
int *i)
{
DISK_READ(x->child[i]);
struct tree_node *p_child = x->child[*i];
if (p_child->num >= tree_degree) {
return tree_delete(t, p_child, key, i);
}
//情况3a,p_child只包含tree_degree-1个关键字
struct tree_node *y = NULL;
//p_child不是最左子结点,则有左兄弟
if (*i > 0) {
DISK_READ(x->child[*i - 1]);
y = x->child[*i - 1];
}
if (y != NULL && y->num >= tree_degree) {
tree_node_insert_key_child(p_child, x->key[*i - 1], 0,
y->child[y->num], 0);
x->key[*i - 1] = y->key[y->num - 1];
tree_node_delete_key_child(y, y->num - 1, y->num);
return tree_delete(t, p_child, key, i);
}
struct tree_node *z = NULL;
//p_child不是最右子结点,则有右兄弟
if (*i < x->num) {
DISK_READ(x->child[*i + 1]);
z = x->child[*i + 1];
}
if (z != NULL && z->num >= tree_degree) {
tree_node_insert_key_child(p_child, x->key[*i],
p_child->num, z->child[0],
p_child->num + 1);
x->key[*i] = z->key[0];
tree_node_delete_key_child(z, 0, 0);
return tree_delete(t, p_child, key, i);
}
//情况3b,p_child及其兄弟都包含tree_degree-1个关键字,p_chaild合并进左兄弟
if (y != NULL) {
tree_union_child(t, x, *i - 1, y, p_child);
return tree_delete(t, y, key, i);
}
//情况3b,p_child及其兄弟都包含tree_degree-1个关键字,右兄弟合并进p_child
if (z != NULL) {
tree_union_child(t, x, *i, p_child, z);
return tree_delete(t, p_child, key, i);
}
return NULL;
}
struct tree_node *tree_delete(tree t, struct tree_node *x, void *key, int *i)
{
*i = 0;
while (*i < x->num && t->comp(key, x->key[*i]) > 0) {
++*i;
}
if (*i < x->num && t->comp(key, x->key[*i]) == 0) {
if (x->leaf) {
return tree_delete_from_leaf(x, i);
} else {
return tree_delete_from_node(t, x, key, i);
}
}
return tree_delete_from_child(t, x, key, i);
}
int cmp_int(const void *p1, const void *p2)
{
const int *pa = p1;
const int *pb = p2;
if (*pa < *pb)
return -1;
if (*pa == *pb)
return 0;
return 1;
}
void print_key(const void *key)
{
const int *p = key;
printf("%d", *p);
}
int main()
{
printf("minimum degree of the B-tree:%d\n", tree_degree);
tree t = tree_create(cmp_int);
for (int i = 0; i < 20; i++) {
int *p = malloc(sizeof(int));
*p = i;
tree_insert(t, p);
}
printf("前序遍历:\n");
tree_preorder_walk(t->root, 0, print_key);
int index;
int key = 0;
struct tree_node *p = tree_search(t, t->root, &key, &index);
if (p != NULL) {
printf("查找关键字:%d成功\n", key);
printf("删除关键字:%d\n", key);
struct tree_node *del = tree_delete(t, t->root, &key, &index);
if (del != NULL) {
free(del->key[index]);
}
p = tree_search(t, t->root, &key, &index);
if (p == NULL) {
printf("删除关键字:%d成功\n", key);
}
printf("删除后,前序遍历:\n");
tree_preorder_walk(t->root, 0, print_key);
}
tree_destroy(t, free);
return 0;
}