只经过少量测试, 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