只经过少量测试, malloc() 没有判断 是否为空
delete insert 假设 传进来的不是NULL
B_TREE
gcc 编译
/*
* precursor 返回值应该是 k 而不是指针,返回指针有可能会降到一个度为T-1的结点上
* 指针重复释放
* 使用宏错误 T ,使用根结点也是 T.
* 文件的操作
* 只经过少量的测试,可能还有问题没有测试出来
* 把思路理清楚很重要
* del 函数代码过长
* 采用最小度方法,对M阶B树,删除要回溯还不明白
*/
#include <stdio.h>
#include <stdlib.h>
#define T (2)
#define NOEXIST (-1)
#define ROOT(_x_) (_x_->c[1])
#define MAX (2*T)
/* error : 2T
* confuse : T and ROOT(T)
*/
struct btree
{
int key[MAX]; //key[0] no used
struct btree *c[MAX+1];
int leaf;
int n;
};
struct btree *allocate_node()
{
struct btree *x = (struct btree *)malloc(sizeof(struct btree));
x->n = 0;
x->leaf = 1;
int i = 0;
for (i = 0; i < MAX; ++i)
{
x->c[i] = NULL;
x->key[i] = 0;
}
x->c[MAX] = NULL;
return x;
}
void split_child(struct btree *x, int i, struct btree *y)
{
struct btree *z = allocate_node();
z->leaf = y->leaf;
z->n = T-1;
int j = 0;
for (j = 1; j <= T-1; ++j)
{
z->key[j] = y->key[j+T];
}
if (!y->leaf)
{
for (j = 1; j <= T; ++j)
{
z->c[j] = y->c[j+T];
}
}
y->n = T-1;
for (j = x->n+1; j >= i+1; --j)
{
x->c[j+1] = x->c[j];
}
x->c[i+1] = z;
for (j = x->n; j >= i; --j)
{
x->key[j+1] = x->key[j];
}
x->key[i] = y->key[T];
x->n += 1;
}
void insert_nofull(struct btree *x, int k)
{
int i = x->n;
if (x->leaf)
{
while (i >=1 && x->key[i] > k)
{
x->key[i+1] = x->key[i];
--i;
}
i += 1;
x->key[i] = k;
x->n += 1;
}
else
{
while (i >= 1 && x->key[i] > k)
{
--i;
}
i += 1;
if (MAX-1 == x->c[i]->n)
{
split_child(x, i, x->c[i]);
if (k > x->key[i])
{
i += 1;
}
}
insert_nofull(x->c[i], k);
}
}
void insert(struct btree *H, int k)
{
struct btree *r = ROOT(H);
if (MAX-1 == r->n)
{
struct btree *s = allocate_node();
s->leaf = 0;
s->n = 0;
s->c[1] = r;
ROOT(H) = s;
split_child(s, 1, r);
insert_nofull(s, k);
}
else
{
insert_nofull(r, k);
}
}
int binsearch(struct btree *x, int k)
{
int left = 0;
int right = x->n+1;
while (left+1 != right)
{
int mid = left + (right-left)/2;
if (x->key[mid] < k)
{
left = mid;
}
else
{
right = mid;
}
}
if (right != x->n+1 && x->key[right] == k)
{
return right;
}
return -1;
}
struct btree *search(struct btree *x, int k)
{
while (NULL != x)
{
int left = 0;
int right = x->n+1;
while (left+1 != right)
{
int mid = left + (right-left)/2;
if (x->key[mid] < k)
{
left = mid;
}
else
{
right = mid;
}
}
if (right != x->n+1 && k == x->key[right])
{
return x;
}
else
{
x= x->c[right];
}
}
return NULL;
}
int precursor(struct btree *x)
{
while (NULL != x->c[x->n+1])
{
x = x->c[x->n+1];
}
return x->key[x->n];
}
int successor(struct btree *x)
{
while (NULL != x->c[1])
{
x = x->c[1];
}
return x->key[1];
}
//将 x->key[i] 与z 合并到 y中
void merge_node(struct btree *x, int i, struct btree *y, struct btree *z) //free(z) ??
{
y->key[T] = x->key[i];
int j = 0;
for (j = 1; j <= T-1; ++j)
{
y->key[j+T] = z->key[j];
}
if (!z->leaf)
{
for (j = 1; j <= T; ++j)
{
y->c[j+T] = z->c[j];
}
}
y->n += T;
for (j = i; j < x->n; ++j)
{
x->key[j] = x->key[j+1];
}
for (j = i+1; j < x->n+1; ++j)
{
x->c[j] = x->c[j+1];
}
x->n -= 1;
free(z);
}
// 删除时 递归删除时 (del, k`)那么怎么删除的值赋给k呢?
// case 1 . x 叶子节点 k在x中,则把k删除,那么如果 x 的度为t-1 ??这里一定会因为从根下降到叶子 <√>
// 会和其他叶子合并
// case 2 . k 在 x 中,x 是内结点.则
// case 2a . y = c[i] (y->n >= t),找到 k 的 precurson (检查是否存在) 递归的删除. <√>
// case 2b . z = c[i+1] (z->n >= t),找到 k 的 successor (检查是否存在) 递归删除 <√>
// case 2c . y z 都只有 t-1, 那么将 y z merge 并将 k 下降到 y` 中, free(z)
// case 3 . k 不在 x 中,找到位置,如果 x->c[i] >= t,则递归的删除. <√>
// case 3a . x->c[i] == t-1 那么将它的 brother->n >= t 的一个key上升到 x,并将 x 中 key 下降到 x->c[i]中
// case 3b . brother->n == t-1 那么将 x->c[i] 与 brother merge 并将 x 中 key 下降到 x>c[i]` 中. free(brother).
// 每次下降都保证 结点至少有 T 个结点
//返回删除后结点的指针
struct btree *del(struct btree *H, struct btree *x, int k) //x != NULL;
{
if (NULL == x)
{
return NULL;
}
int pos = binsearch(x, k);
while (!x->leaf || -1 != pos)
{
if (-1 != pos && x->leaf)
{
int i = pos;
while (i < x->n)
{
x->key[i] = x->key[i+1];
++i;
}
x->n -= 1;
return x;
}
else if (-1 != pos && !x->leaf) //这里会不会出现 z 的key == t-1,不会
{
struct btree *y = x->c[pos];
struct btree *z = NULL;
int new_k = 0;
if (y->n >= T) //success
{
new_k = precursor(y); //这里出现错误,当返回来的是叶子节点并且节点在叶子中,在进入循环时x->n==0
k = new_k; //那么ROOT(H) 就会变成NULL;而实际上并不是这样
x->key[pos] = k;
x = y;
}
else if (x->c[pos+1]->n >= T) //success
{
y = x->c[pos+1];
new_k = successor(y);
k = new_k;
x->key[pos] = k;
x = y;
}
else //success
{
y = x->c[pos];
z = x->c[pos+1];
merge_node(x, pos, y, z); //将x->key[pos] z合并到y中, 合并后 x 为空,要处理一下
if (0 == x->n)
{
ROOT(H) = y; //这里一定是root 因为不会将到 度为T-1的节点上.
free(x);
x = NULL;
}
//free(z); //重复释放两次
x = y;
}
}
else
{
int i = x->n;
while (i >= 1 && x->key[i] > k)
{
--i;
}
i += 1;
if (x->c[i]->n >= T) //success
{
x = x->c[i];
}
else
{
/*这里还要check是否存在
* pre
* next
* */
struct btree *pre = NULL;
struct btree *cur = x->c[i];
struct btree *next = NULL;
if (i-1 >= 1 && x->c[i-1]->n >= T) //success
{
pre = x->c[i-1];
int j = 0;
for (j = cur->n; j >= 1; --j)
{
cur->key[j+1] = cur->key[j];
}
cur->key[1] = x->key[i-1];
if (!pre->leaf)
{
for (j = cur->n+1; j >= 1; --j)
{
cur->c[j+1] = cur->c[j];
}
cur->c[1] = pre->c[pre->n+1];
}
cur->n += 1;
x->key[i-1] = pre->key[pre->n];
pre->n -= 1;
}
else if (i <= x->n && x->c[i+1]->n >= T)
{
next = x->c[i+1];
cur->key[cur->n+1] = x->key[i];
x->key[i] = next->key[1];
cur->n += 1;
int j = 0;
for (j = 1; j <= next->n; ++j)
{
next->key[j] = next->key[j+1];
}
if (!next->leaf)
{
cur->c[cur->n+1] = next->c[1];
for (j = 1; j <= next->n+1; ++j)
{
next->c[j] = next->c[j+1];
}
}
next->n -= 1;
}
else if (i-1 >= 1) // success
{
pre = x->c[i-1];
merge_node(x, i-1, pre, cur);
if (0 == x->n)
{
ROOT(H) = pre;
free(x);
x = pre;
}
}
else //success
{
next = x->c[i+1];
merge_node(x, i, cur, next);
if (0 == x->n)
{
ROOT(H) = cur;
free(x);
x = cur;
}
}
}
}
pos = binsearch(x, k);
}
return NULL;
}
void creat(struct btree *H)
{
struct btree *x = allocate_node();
x->leaf = 1;
x->n = 0;
ROOT(H) = x;
}
void print_node(struct btree *x)
{
int i = 0;
for (i = 1; i < x->n; ++i)
{
printf("%d-->", x->key[i]);
}
printf("%d\n", x->key[x->n]); // x->key[i] 如果i没有增加,这里有危险
}
void print_btree(struct btree *x)
{
if (NULL != x)
{
print_node(x);
int i = 0;
for (i = 1; i <= x->n+1; ++i)
{
print_btree(x->c[i]);
}
}
}
int main()
{
struct btree *H = allocate_node();
ROOT(H) = NULL;
while (1)
{
printf("\t\t 1 . creat\n");
printf("\t\t 2 . insert\n");
printf("\t\t 3 . search\n");
printf("\t\t 4 . delete\n");
printf("\t\t 5 . print\n");
printf("\t\t 0 . exit\n");
int sel = 0;
scanf("%d", &sel);
switch (sel)
{
case 1:
creat(H);
break;
case 2:
{
int k = 0;
printf("insert : \n");
while (EOF != scanf("%d", &k))
{
insert(H, k); // ROOT(H) != NULL;
}
}
break;
case 3:
{
int k = 0;
printf("search : ");
scanf("%d", &k);
struct btree *x = search(ROOT(H), k);
if (x)
{
print_node(x);
}
}
break;
case 4:
{
int k = 0;
printf("delete : ");
scanf("%d", &k);
struct btree *x = del(H, ROOT(H), k);
if (x)
{
if (0 == x->n) //是不是肯定是根节点, 这里要考虑会不会降到别的节点上
{
free(x);
x = NULL;
ROOT(H) = NULL;
}
else
{
print_node(x);
}
}
}
break;
case 5:
{
print_btree(ROOT(H));
}
break;
case 0:
{
return 0;
}
default:
{
printf("error : input num is error !\n");
}
break;
}
}
return 0;
}
B TREE 插入 3 阶不行
5 阶B-TREE
key : ceil(5/2)-1 ~ 5-1 (2 ~ 4)
delete 5 阶时,
当left brother 只有 2 个,right brother也只有2个
那么 merge 就是 变成了 5 个了,超过了范围。
B+TREE
/*1 . 开始的时候因为B+TREE 定义,所以在插入时就卡住了,
* 看到july的B+TREE 图有疑问,要是一个更小的值插入进来
* 那么不是要更新所有的index
* 2 . B+TREE 实现有两种
* 2a. 度为m的b+tree,内部索引点和叶子节点的 key 最多m-1,
* pointer最多m
* 2b.度为m的b+tree,内部索引点和叶子节点的 key 最多m,
* pointer最多m,根节点至少2个key,下层节点的key是上层"最大值"(或者"最小值")的复写
* 如果树高是多层的,那么这时内部索引节点的key,可能被复写多次
* 程序中出现的错误
* 1 . 39 i <= 2*M
* 2 . 338 shift_to_left 为什么i-1
* 3 . merge_node(x, i-1, pre, x-c[i])
* 4 . merge shift leaf node 区别
*/
#include <stdio.h>
#include <stdlib.h>
#define M (2)
#define ROOT(_x_) (_x_->c[1]) //root of bplustree
#define DATA(_x_) (_x_->c[1]) //root of leaf
typedef struct BPlusNode
{
int k[2*M];
struct BPlusNode *c[2*M+1];
int leaf;
int n;
struct BPlusNode *next;
}BPlusNode;
BPlusNode *allocate_node()
{
BPlusNode *x = (BPlusNode *)malloc(sizeof(BPlusNode)); // x != NULL;
x->leaf = 1;
x->n = 0;
x->next = NULL;
int i = 0;
for (i = 1; i < 2*M; ++i)
{
x->k[i] = 0; // error : x->k[2*M] overflow
x->c[i] = NULL;
}
x->c[2*M] = NULL;
return x;
}
void creat(BPlusNode *T, BPlusNode *D)
{
BPlusNode *x = allocate_node();
//DISK-WRITE(x);
ROOT(T) = x;
DATA(D) = x; //这里不会出现问题
} //1 . merge 只会向前merge
//2 . shift 最少还会剩下一了
void split_node(BPlusNode *x, int pos, BPlusNode *y)
{
BPlusNode *z = allocate_node();
z->leaf = y->leaf;
z->n = M-1;
int i = 0;
for (i = 1; i < M; ++i)
{
z->k[i] = y->k[i+M];
}
if (!y->leaf)
{
for (i = 1; i <= M; ++i)
{
z->c[i] = y->c[i+M];
}
}
y->n = M-1;
if (y->leaf)
{
y->n += 1; // error : leaf 最后一个留在leaf中
}
for (i = x->n+1; i > pos; --i)
{
x->c[i+1] = x->c[i];
}
x->c[pos+1] = z;
for (i = x->n; i >= pos; --i) //??这样key 比 c 就多一个??
{ // 两种实现方法
x->k[i+1] = x->k[i];
}
x->k[pos] = y->k[M];
x->n += 1;
if (y->leaf)
{
z->next = y->next;
y->next = z;
}
}
void insert_nonfull(BPlusNode *x, int key)
{
int i = x->n;
if (x->leaf)
{
while (i > 0 && key < x->k[i])
{
x->k[i+1] = x->k[i];
--i;
}
i += 1;
x->k[i] = key;
x->n += 1;
}
else
{
while (i > 0 && key < x->k[i])
{
--i;
}
i += 1;
if (2*M-1 == x->c[i]->n)
{
split_node(x, i, x->c[i]);
if (key > x->k[i])
{
i += 1;
}
}
insert_nonfull(x->c[i], key);
}
}
void insert_node(BPlusNode *T, int key)
{
BPlusNode *r = ROOT(T);
if (2*M-1 == r->n)
{
BPlusNode *x = allocate_node();
ROOT(T) = x;
x->c[1] = r;
x->leaf = 0;
x->n = 0;
split_node(x, 1, r);
insert_nonfull(x, key);
}
else
{
insert_nonfull(r, key);
}
}
/*为什么会合并,因为 y z num == M-1*/
void merge_node(BPlusNode *x, int pos/*position of key*/, BPlusNode *y, BPlusNode *z) //从x中拿出一个key && z merge y
{
int i = 0;
if (y->leaf)
{
for (i = 1; i <= z->n; ++i) // leaf 不用 y->k[M] = x->k[pos];
{ // case 1 . y->k[M-1] == x->k[pos]
y->k[i+M-1] = z->k[i];// case 2 . x->k[pos] 已经删除
}
y->n = 2*M-2;
}
else
{
y->k[M] = x->k[pos]; //test success
for (i = 1; i <= z->n; ++i)
{
y->k[i+M] = z->k[i]; // 到底 i+M 还是 i+M-1
}
for (i = 1; i <= z->n+1; ++i)
{
y->c[i+M] = z->c[i];
}
y->n = 2*M-1;
}
for (i = pos; i < x->n; ++i)
{
x->k[i] = x->k[i+1];
}
for (i = pos+1; i <= x->n; ++i)
{
x->c[i] = x->c[i+1];
}
x->n -= 1;
if (y->leaf)
{
y->next = z->next;
}
free(z);
}
int binsearch(BPlusNode *x, int key)
{
int left = 0;
int right = x->n+1;
while (left+1 != right)
{
int mid = left + (right-left)/2;
if (x->k[mid] < key)
{
left = mid; //error : leaf = mid+1;
}
else
{
right = mid;
}
}
if (right <= x->n && x->k[right] == key)
{
return right;
}
return 0;
}
void shift_to_left(BPlusNode *x, int pos, BPlusNode *y, BPlusNode *z) // leaf test
{
if (!z->leaf)
{
y->k[y->n+1] = x->k[pos]; // y 记得 +1
}
else
{
y->k[y->n+1] = z->k[1];
}
x->k[pos] = z->k[1];
int i = 0;
for (i = 1; i < z->n; ++i)
{
z->k[i] = z->k[i+1];
}
if (!z->leaf) //test
{
y->c[y->n+2] = z->c[1];
for (i = 1; i <= z->n; ++i)
{
z->c[i] = z->c[i+1]; //cover
}
}
y->n += 1;
z->n -= 1;
}
void shift_to_right(BPlusNode *x, int pos, BPlusNode *y, BPlusNode *z)
{
int i = 0;
for (i = x->n; i > 0; --i)
{
y->k[i+1] = y->k[i];
}
if (!y->leaf)
{
y->k[1] = x->k[pos];
x->k[pos] = z->k[z->n];
}
else
{
y->k[1] = z->k[z->n];
x->k[pos] = z->k[z->n-1]; //leaf test
}
if (!y->leaf) //test
{
for (i = y->n+1; i >= 1; --i)
{
y->c[i+1] = y->c[i];
}
y->c[1] = z->c[z->n+1];
//z->c[z->n+1] = NULL;
}
y->n += 1;
z->n -= 1;
}
/* b tree case
* 1 . key in the node and node is leaf
* 2 . key in the node and node isn't leaf
* 2a. prececursor
* 2b. successor
* 2c. merge precessor and successor
* 3 . key isn't in the node
* 3a. brother (pre or next)
* 3b. merge brother
* b+tree 就相当于在内结点中找不到key case 3
* b+tree
* 1a.brother
* 1b.merge brother
* leaf 相对于 b tree 要另外处理
**/
BPlusNode *delete_nonone(BPlusNode *x, int key)
{
while (1)
{
if (x->leaf)
{
int pos = binsearch(x, key);
if (pos)
{
int i = pos;
while (i < x->n)
{
x->k[i] = x->k[i+1];
++i;
}
x->n -= 1;
return x;
}
else
{
printf("error : no the key int the leaf !\n");
return NULL;
}
}
else
{
int i = x->n;
while (i > 0 && x->k[i] >= key)
{
--i;
}
i += 1;
BPlusNode *pre = NULL;
BPlusNode *next = NULL;
if (x->c[i]->n >= M)
{
x = x->c[i]; //test
}
else if (i > 1 && x->c[i-1]->n >= M)
{
pre = x->c[i-1];
shift_to_right(x, i-1, x->c[i], pre); // i 的值这里奇怪
x = x->c[i]; // i-1为什么?
} // pre and x->c[i] 中间的是i-1
else if (i <= x->n && x->c[i+1]->n >= M)
{
next = x->c[i+1];
shift_to_left(x, i, x->c[i], next); //要替换key的位置为什么不减1,c[i] and next is i
x = x->c[i];
}
else if (i > 1)
{
pre = x->c[i-1];
merge_node(x, i-1, pre, x->c[i]); // leaf success
x = pre;
}
else
{
next = x->c[i+1];
merge_node(x, i, x->c[i], next); //leaf success
x = x->c[i];
}
}
}
}
BPlusNode *delete_node(BPlusNode *T, int key)
{
BPlusNode *x = ROOT(T);
if (1 == x->n) //特殊情况,有可能删除根节点
{
BPlusNode *y = x->c[1];
BPlusNode *z = x->c[2];
if (y && z && M-1 == y->n && M-1 == z->n)
{
merge_node(x, 1, y, z);
free(x);
x = y;
ROOT(T) = x;
}
}
return delete_nonone(x, key);
}
void print_node(BPlusNode *x);
int search_node(BPlusNode *x, int key)
{
BPlusNode *y = NULL;
while (x)
{
y = x;
int i = x->n;
while (i > 0 && key <= x->k[i])
{
--i;
}
i += 1;
x = x->c[i];
}
print_node(y);
return binsearch(y, key);
}
void print_node(BPlusNode *x)
{
int i = 0;
for (i = 1; i < x->n; ++i)
{
printf("%d--", x->k[i]);
}
printf("%d\n", x->k[x->n]);
}
void print_tree(BPlusNode *x)
{
if (NULL != x)
{
print_node(x);
int i = 0;
for (i = 1; i <= x->n+1; ++i)
{
print_tree(x->c[i]);
}
}
}
void print_leaf(BPlusNode *D)
{
BPlusNode *x = DATA(D);
printf("leaf :\n");
while (NULL != x)
{
int i = 0;
for (i = 1; i < x->n; ++i)
{
printf("%d-->", x->k[i]);
}
printf("%d\n", x->k[x->n]);
x = x->next;
}
}
int main()
{
BPlusNode *T = allocate_node();
ROOT(T) = NULL;
BPlusNode *D = allocate_node();
DATA(D) = NULL;
int flag = 1;
while (flag)
{
printf("\n\t\t1 . creat");
printf("\n\t\t2 . insert");
printf("\n\t\t3 . delete");
printf("\n\t\t4 . search");
printf("\n\t\t5 . print");
printf("\n\t\t6 . print leaf");
printf("\n\t\t0 . exit\n");
int sel = 0;
scanf("%d", &sel);
switch (sel)
{
case 1:
{
creat(T, D);
}break;
case 2:
{
printf("insert node : \n");
int key = 0;
while (EOF != scanf("%d", &key))
{
insert_node(T, key);
}
}break;
case 3:
{
printf("delete node : \n");
int key = 0;
scanf("%d", &key);
BPlusNode *x = delete_node(T, key);
if (x)
{
if (0 == x->n)
{
free(x);
ROOT(T) = NULL;
DATA(D) = NULL;
}
else
{
print_node(x);
}
}
}break;
case 4:
{
printf("search node :\n");
int key = 0;
scanf("%d", &key);
int pos = search_node(ROOT(T), key);
if (pos)
{
printf("found!\n");
}
}break;
case 5:
{
print_tree(ROOT(T));
}break;
case 6:
{
print_leaf(D);
}break;
case 0:
flag = 0;
break;
default:;
}
}
return 0;
}
参考:
http://163lixianfeng.blog.163.com/blog/static/137268212011475333290/
http://blog.oldsharp.info/btree_definition/ B TREE 定义详细分析
http://blog.chinaunix.net/uid-20196318-id-3030529.html