标签:
B树的定义
假设B树的度为t(t>=2),则B树满足如下要求:(参考算法导论)
(1) 每个非根节点至少包含t-1个关键字,t个指向子节点的指针;至多包含2t-1个关键字,2t个指向子女的指针(叶子节点的子女为空)。
(2) 节点的所有key按非降序存放,假设节点的关键字分别为K[1], K[2] … K[n], 指向子女的指针分别为P[1], P[2]…P[n+1],其中n为节点关键字的个数。则有:
P[1] <= K[1] <= P[2] <= K[2] …..<= K[n] <= P[n+1] // 这里P[n]也指其指向的关键字
(3) 若根节点非空,则根节点至少包含两个子女;
(4) 所有的叶子节点都在同一层。
B树的搜索,search(root, target)
从root出发,对每个节点,找到大于或等于target关键字中最小的K[i],如果K[i]与target相等,则查找成功;否则在P[i]中递归搜索target,直到到达叶子节点,如仍未找到则说明关键字不在B树中,查找失败。
B树的插入,insert(root, target)
B树的插入需要沿着搜索的路径从root一直到叶节点,根据B树的规则,每个节点的关键字个数在[t-1, 2t-1]之间,故当target要加入到某个叶子时,如果该叶子节点已经有2t-1个关键字,则再加入target就违反了B树的定义,这时就需要对该叶子节点进行分裂,将叶子以中间节点为界,分成两个包含t-1个关键字的子节点,同时把中间节点提升到该叶子的父节点中,如果这样使得父节点的关键字个数超过2t-1,则要继续向上分裂,直到根节点,根节点的分裂会使得树加高一层。
上面的过程需要回溯,那么能否从根下降到叶节点后不回溯就能完成节点的插入呢?答案是肯定的,核心思想就是未雨绸缪,在下降的过程中,一旦遇到已满的节点(关键字个数为2t-1),就就对该节点进行分裂,这样就保证在叶子节点需要分裂时,其父节点一定是非满的,从而不需要再向上回溯。
B树的删除,delete(root, target)
在删除B树节点时,为了避免回溯,当遇到需要合并的节点时就立即执行合并,B树的删除算法如下:从root向叶子节点按照search规律遍历:
(1) 如果target在叶节点x中,则直接从x中删除target,情况(2)和(3)会保证当再叶子节点找到target时,肯定能借节点或合并成功而不会引起父节点的关键字个数少于t-1。
(2) 如果target在分支节点x中:
(a) 如果x的左分支节点y至少包含t个关键字,则找出y的最右的关键字prev,并替换target,并在y中递归删除prev。
(b) 如果x的右分支节点z至少包含t个关键字,则找出z的最左的关键字next,并替换target,并在z中递归删除next。
(c) 否则,如果y和z都只有t-1个关键字,则将targe与z合并到y中,使得y有2t-1个关键字,再从y中递归删除target。
(3) 如果关键字不在分支节点x中,则必然在x的某个分支节点p[i]中,如果p[i]节点只有t-1个关键字。
(a) 如果p[i-1]拥有至少t个关键字,则将x的某个关键字降至p[i]中,将p[i-1]的最大节点上升至x中。
(b) 如果p[i+1]拥有至少t个关键字,则将x个某个关键字降至p[i]中,将p[i+1]的最小关键字上升至x个。
(c) 如果p[i-1]与p[i+1]都拥有t-1个关键字,则将p[i]与其中一个兄弟合并,将x的一个关键字降至合并的节点中,成为中间关键字。
btree.c
#include <stdio.h> #include <stdlib.h> /** * @brief the degree of btree * key per node: [M-1, 2M-1] * child per node: [M, 2M] */ #define M 2 typedef struct btree_node { int k[2*M-1]; struct btree_node *p[2*M]; int num; bool is_leaf; } btree_node; /** * @brief allocate a new btree node * default: is_leaf == true * * @return pointer of new node */ btree_node *btree_node_new(); /** * @brief create a btree root * * @return pointer of btree root */ btree_node *btree_create(); /** * @brief split child if num of key in child exceed 2M-1 * * @param parent: parent of child * @param pos: p[pos] points to child * @param child: the node to be splited * * @return */ int btree_split_child(btree_node *parent, int pos, btree_node *child); /** * @brief insert a value into btree * the num of key in node less than 2M-1 * * @param node: tree root * @param target: target to insert */ void btree_insert_nonfull(btree_node *node, int target); /** * @brief insert a value into btree * * @param root: tree root * @param target: target to insert * * @return: new root of tree */ btree_node* btree_insert(btree_node *root, int target); /** * @brief merge y, z and root->k[pos] to left * this appens while y and z both have M-1 keys * * @param root: parent node * @param pos: postion of y * @param y: left node to merge * @param z: right node to merge */ void btree_merge_child(btree_node *root, int pos, btree_node *y, btree_node *z); /** * @brief delete a vlue from btree * * @param root: btree root * @param target: target to delete * * @return: new root of tree */ btree_node *btree_delete(btree_node *root, int target); /** * @brief delete a vlue from btree * root has at least M keys * * @param root: btree root * @param target: target to delete * * @return */ void btree_delete_nonone(btree_node *root, int target); /** * @brief find the rightmost value * * @param root: root of tree * * @return: the rightmost value */ int btree_search_predecessor(btree_node *root); /** * @brief find the leftmost value * * @param root: root of tree * * @return: the leftmost value */ int btree_search_successor(btree_node *root); /** * @brief shift a value from z to y * * @param root: btree root * @param pos: position of y * @param y: left node * @param z: right node */ void btree_shift_to_left_child(btree_node *root, int pos, btree_node *y, btree_node *z); /** * @brief shift a value from z to y * * @param root: btree root * @param pos: position of y * @param y: left node * @param z: right node */ void btree_shift_to_right_child(btree_node *root, int pos, btree_node *y, btree_node *z); /** * @brief inorder traverse the btree * * @param root: root of treee */ void btree_inorder_print(btree_node *root); /** * @brief level print the btree * * @param root: root of tree */ void btree_level_display(btree_node *root); btree_node *btree_node_new() { btree_node *node = (btree_node *)malloc(sizeof(btree_node)); if(NULL == node) { return NULL; } for(int i = 0; i < 2 * M -1; i++) { node->k[i] = 0; } for(int i = 0; i < 2 * M; i++) { node->p[i] = NULL; } node->num = 0; node->is_leaf = true; } btree_node *btree_create() { btree_node *node = btree_node_new(); if(NULL == node) { return NULL; } return node; } int btree_split_child(btree_node *parent, int pos, btree_node *child) { btree_node *new_child = btree_node_new(); if(NULL == new_child) { return -1; } new_child->is_leaf = child->is_leaf; new_child->num = M - 1; for(int i = 0; i < M - 1; i++) { new_child->k[i] = child->k[i+M]; } if(false == new_child->is_leaf) { for(int i = 0; i < M; i++) { new_child->p[i] = child->p[i+M]; } } child->num = M - 1; for(int i = parent->num; i > pos; i--) { parent->p[i+1] = parent->p[i]; } parent->p[pos+1] = new_child; for(int i = parent->num - 1; i >= pos; i--) { parent->k[i+1] = parent->k[i]; } parent->k[pos] = child->k[M-1]; parent->num += 1; } void btree_insert_nonfull(btree_node *node, int target) { if(1 == node->is_leaf) { int pos = node->num; while(pos >= 1 && target < node->k[pos-1]) { node->k[pos] = node->k[pos-1]; pos--; } node->k[pos] = target; node->num += 1; } else { int pos = node->num; while(pos > 0 && target < node->k[pos-1]) { pos--; } if(2 * M -1 == node->p[pos]->num) { btree_split_child(node, pos, node->p[pos]); if(target > node->k[pos]) { pos++; } } btree_insert_nonfull(node->p[pos], target); } } btree_node* btree_insert(btree_node *root, int target) { if(NULL == root) { return NULL; } if(2 * M - 1 == root->num) { btree_node *node = btree_node_new(); if(NULL == node) { return root; } node->is_leaf = 0; node->p[0] = root; btree_split_child(node, 0, root); btree_insert_nonfull(node, target); return node; } else { btree_insert_nonfull(root, target); return root; } } void btree_merge_child(btree_node *root, int pos, btree_node *y, btree_node *z) { y->num = 2 * M - 1; for(int i = M; i < 2 * M - 1; i++) { y->k[i] = z->k[i-M]; } y->k[M-1] = root->k[pos]; if(false == z->is_leaf) { for(int i = M; i < 2 * M; i++) { y->p[i] = z->p[i-M]; } } for(int j = pos + 1; j < root->num; j++) { root->k[j-1] = root->k[j]; root->p[j] = root->p[j+1]; } root->num -= 1; free(z); } btree_node *btree_delete(btree_node *root, int target) { if(1 == root->num) { btree_node *y = root->p[0]; btree_node *z = root->p[1]; if(NULL != y && NULL != z && M - 1 == y->num && M - 1 == z->num) { btree_merge_child(root, 0, y, z); free(root); btree_delete_nonone(y, target); return y; } else { btree_delete_nonone(root, target); return root; } } else { btree_delete_nonone(root, target); return root; } } void btree_delete_nonone(btree_node *root, int target) { if(true == root->is_leaf) { int i = 0; while(i < root->num && target > root->k[i]) i++; if(target == root->k[i]) { for(int j = i + 1; j < 2 * M - 1; j++) { root->k[j-1] = root->k[j]; } root->num -= 1; } else { printf("target not found\n"); } } else { int i = 0; btree_node *y = NULL, *z = NULL; while(i < root->num && target > root->k[i]) i++; if(i < root->num && target == root->k[i]) { y = root->p[i]; z = root->p[i+1]; if(y->num > M - 1) { int pre = btree_search_predecessor(y); root->k[i] = pre; btree_delete_nonone(y, pre); } else if(z->num > M - 1) { int next = btree_search_successor(z); root->k[i] = next; btree_delete_nonone(z, next); } else { btree_merge_child(root, i, y, z); btree_delete(y, target); } } else { y = root->p[i]; if(i < root->num) { z = root->p[i+1]; } btree_node *p = NULL; if(i > 0) { p = root->p[i-1]; } if(y->num == M - 1) { if(i > 0 && p->num > M - 1) { btree_shift_to_right_child(root, i-1, p, y); } else if(i < root->num && z->num > M - 1) { btree_shift_to_left_child(root, i, y, z); } else if(i > 0) { btree_merge_child(root, i-1, p, y); // note y = p; } else { btree_merge_child(root, i, y, z); } btree_delete_nonone(y, target); } else { btree_delete_nonone(y, target); } } } } int btree_search_predecessor(btree_node *root) { btree_node *y = root; while(false == y->is_leaf) { y = y->p[y->num]; } return y->k[y->num-1]; } int btree_search_successor(btree_node *root) { btree_node *z = root; while(false == z->is_leaf) { z = z->p[0]; } return z->k[0]; } void btree_shift_to_right_child(btree_node *root, int pos, btree_node *y, btree_node *z) { z->num += 1; for(int i = z->num -1; i > 0; i--) { z->k[i] = z->k[i-1]; } z->k[0]= root->k[pos]; root->k[pos] = y->k[y->num-1]; if(false == z->is_leaf) { for(int i = z->num; i > 0; i--) { z->p[i] = z->p[i-1]; } z->p[0] = y->p[y->num]; } y->num -= 1; } void btree_shift_to_left_child(btree_node *root, int pos, btree_node *y, btree_node *z) { y->num += 1; y->k[y->num-1] = root->k[pos]; root->k[pos] = z->k[0]; for(int j = 1; j < z->num; j++) { z->k[j-1] = z->k[j]; } if(false == z->is_leaf) { y->p[y->num] = z->p[0]; for(int j = 1; j <= z->num; j++) { z->p[j-1] = z->p[j]; } } z->num -= 1; } void btree_inorder_print(btree_node *root) { if(NULL != root) { btree_inorder_print(root->p[0]); for(int i = 0; i < root->num; i++) { printf("%d ", root->k[i]); btree_inorder_print(root->p[i+1]); } } } void btree_level_display(btree_node *root) { // just for simplicty, can‘t exceed 200 nodes in the tree btree_node *queue[200] = {NULL}; int front = 0; int rear = 0; queue[rear++] = root; while(front < rear) { btree_node *node = queue[front++]; printf("["); for(int i = 0; i < node->num; i++) { printf("%d ", node->k[i]); } printf("]"); for(int i = 0; i <= node->num; i++) { if(NULL != node->p[i]) { queue[rear++] = node->p[i]; } } } printf("\n"); } int main() { int arr[] = {18, 31, 12, 10, 15, 48, 45, 47, 50, 52, 23, 30, 20}; btree_node *root = btree_create(); for(int i = 0; i < sizeof(arr) / sizeof(int); i++) { root = btree_insert(root, arr[i]); btree_level_display(root); } //int todel[] = {15, 18, 23, 30, 31, 52, 50}; int todel[] = {52}; for(int i = 0; i < sizeof(todel) / sizeof(int); i++) { printf("after delete %d\n", todel[i]); root = btree_delete(root, todel[i]); btree_level_display(root); } return 0; }
B+树
与B树不同的时,B+树的关键字都存储在叶子节点,分支节点均为索引,在实现上大致与B树类似,在几个细节稍有不同。
(1) 数据结构中增加prev,next指针,用于将叶子节点串成有序双向链表。
(2) 在节点分裂的时候,如果分裂的节点为叶子,则需要把中间节点保留在左(或右)边的分支上,并且需要更新prev和next。
(3) 在节点合的时候,如果合并的节点为叶子,不需要把跟节点下降为中间节点,并且需要更新prev和next。
(4) 在向邻接节点借节点时,借来的关键字并不是父节点的关键字,而是邻接点的关键字,并根据实际情况更新父节点的索引。
bplustree.c
#include <stdio.h> #include <stdlib.h> /** * @brief the degree of btree * key per node: [M-1, 2M-1] * child per node: [M, 2M] */ #define M 2 // the degree of btree typedef struct btree_node { int k[2*M-1]; struct btree_node *p[2*M]; int num; bool is_leaf; struct btree_node *prev; // use one struct just for simple struct btree_node *next; } btree_node; /** * @brief allocate a new btree node * default: is_leaf == true * * @return pointer of new node */ btree_node *btree_node_new(); /** * @brief create a btree root * * @return pointer of btree root */ btree_node *btree_create(); /** * @brief split child if num of key in child exceed 2M-1 * * @param parent: parent of child * @param pos: p[pos] points to child * @param child: the node to be splited * * @return */ int btree_split_child(btree_node *parent, int pos, btree_node *child); /** * @brief insert a value into btree * the num of key in node less than 2M-1 * * @param node: tree root * @param target: target to insert */ void btree_insert_nonfull(btree_node *node, int target); /** * @brief insert a value into btree * * @param root: tree root * @param target: target to insert * * @return: new root of tree */ btree_node* btree_insert(btree_node *root, int target); /** * @brief merge y, z and root->k[pos] to left * this appens while y and z both have M-1 keys * * @param root: parent node * @param pos: postion of y * @param y: left node to merge * @param z: right node to merge */ void btree_merge_child(btree_node *root, int pos, btree_node *y, btree_node *z); /** * @brief delete a vlue from btree * * @param root: btree root * @param target: target to delete * * @return: new root of tree */ btree_node *btree_delete(btree_node *root, int target); /** * @brief delete a vlue from btree * root has at least M keys * * @param root: btree root * @param target: target to delete * * @return */ void btree_delete_nonone(btree_node *root, int target); /** * @brief find the rightmost value * * @param root: root of tree * * @return: the rightmost value */ int btree_search_predecessor(btree_node *root); /** * @brief find the leftmost value * * @param root: root of tree * * @return: the leftmost value */ int btree_search_successor(btree_node *root); /** * @brief shift a value from z to y * * @param root: btree root * @param pos: position of y * @param y: left node * @param z: right node */ void btree_shift_to_left_child(btree_node *root, int pos, btree_node *y, btree_node *z); /** * @brief shift a value from z to y * * @param root: btree root * @param pos: position of y * @param y: left node * @param z: right node */ void btree_shift_to_right_child(btree_node *root, int pos, btree_node *y, btree_node *z); /** * @brief inorder traverse the btree * * @param root: root of treee */ void btree_inorder_print(btree_node *root); /** * @brief print tree linearly using prev/next pointer * * @param root: root of tree */ void btree_linear_print(btree_node *root); /** * @brief level print the btree * * @param root: root of tree */ void btree_level_display(btree_node *root); btree_node *btree_node_new() { btree_node *node = (btree_node *)malloc(sizeof(btree_node)); if(NULL == node) { return NULL; } for(int i = 0; i < 2 * M -1; i++) { node->k[i] = 0; } for(int i = 0; i < 2 * M; i++) { node->p[i] = NULL; } node->num = 0; node->is_leaf = true; node->prev = NULL; node->next = NULL; } btree_node *btree_create() { btree_node *node = btree_node_new(); if(NULL == node) { return NULL; } node->next = node; node->prev = node; return node; } int btree_split_child(btree_node *parent, int pos, btree_node *child) { btree_node *new_child = btree_node_new(); if(NULL == new_child) { return -1; } new_child->is_leaf = child->is_leaf; new_child->num = M - 1; for(int i = 0; i < M - 1; i++) { new_child->k[i] = child->k[i+M]; } if(false == new_child->is_leaf) { for(int i = 0; i < M; i++) { new_child->p[i] = child->p[i+M]; } } child->num = M - 1; if(true == child->is_leaf) { child->num++; // if leaf, keep the middle ele, put it in the left } for(int i = parent->num; i > pos; i--) { parent->p[i+1] = parent->p[i]; } parent->p[pos+1] = new_child; for(int i = parent->num - 1; i >= pos; i--) { parent->k[i+1] = parent->k[i]; } parent->k[pos] = child->k[M-1]; parent->num += 1; // update link if(true == child->is_leaf) { new_child->next = child->next; child->next->prev = new_child; new_child->prev = child; child->next = new_child; } } void btree_insert_nonfull(btree_node *node, int target) { if(1 == node->is_leaf) { int pos = node->num; while(pos >= 1 && target < node->k[pos-1]) { node->k[pos] = node->k[pos-1]; pos--; } node->k[pos] = target; node->num += 1; } else { int pos = node->num; while(pos > 0 && target < node->k[pos-1]) { pos--; } if(2 * M -1 == node->p[pos]->num) { btree_split_child(node, pos, node->p[pos]); if(target > node->k[pos]) { pos++; } } btree_insert_nonfull(node->p[pos], target); } } btree_node* btree_insert(btree_node *root, int target) { if(NULL == root) { return NULL; } if(2 * M - 1 == root->num) { btree_node *node = btree_node_new(); if(NULL == node) { return root; } node->is_leaf = 0; node->p[0] = root; btree_split_child(node, 0, root); btree_insert_nonfull(node, target); return node; } else { btree_insert_nonfull(root, target); return root; } } void btree_merge_child(btree_node *root, int pos, btree_node *y, btree_node *z) { if(true == y->is_leaf) { y->num = 2 * M - 2; for(int i = M; i < 2 * M - 1; i++) { y->k[i-1] = z->k[i-M]; } } else { y->num = 2 * M - 1; for(int i = M; i < 2 * M - 1; i++) { y->k[i] = z->k[i-M]; } y->k[M-1] = root->k[pos]; for(int i = M; i < 2 * M; i++) { y->p[i] = z->p[i-M]; } } for(int j = pos + 1; j < root->num; j++) { root->k[j-1] = root->k[j]; root->p[j] = root->p[j+1]; } root->num -= 1; // update link if(true == y->is_leaf) { y->next = z->next; z->next->prev = y; } free(z); } btree_node *btree_delete(btree_node *root, int target) { if(1 == root->num) { btree_node *y = root->p[0]; btree_node *z = root->p[1]; if(NULL != y && NULL != z && M - 1 == y->num && M - 1 == z->num) { btree_merge_child(root, 0, y, z); free(root); btree_delete_nonone(y, target); return y; } else { btree_delete_nonone(root, target); return root; } } else { btree_delete_nonone(root, target); return root; } } void btree_delete_nonone(btree_node *root, int target) { if(true == root->is_leaf) { int i = 0; while(i < root->num && target > root->k[i]) i++; if(target == root->k[i]) { for(int j = i + 1; j < 2 * M - 1; j++) { root->k[j-1] = root->k[j]; } root->num -= 1; } else { printf("target not found\n"); } } else { int i = 0; btree_node *y = NULL, *z = NULL; while(i < root->num && target > root->k[i]) i++; y = root->p[i]; if(i < root->num) { z = root->p[i+1]; } btree_node *p = NULL; if(i > 0) { p = root->p[i-1]; } if(y->num == M - 1) { if(i > 0 && p->num > M - 1) { btree_shift_to_right_child(root, i-1, p, y); } else if(i < root->num && z->num > M - 1) { btree_shift_to_left_child(root, i, y, z); } else if(i > 0) { btree_merge_child(root, i-1, p, y); y = p; } else { btree_merge_child(root, i, y, z); } btree_delete_nonone(y, target); } else { btree_delete_nonone(y, target); } } } int btree_search_predecessor(btree_node *root) { btree_node *y = root; while(false == y->is_leaf) { y = y->p[y->num]; } return y->k[y->num-1]; } int btree_search_successor(btree_node *root) { btree_node *z = root; while(false == z->is_leaf) { z = z->p[0]; } return z->k[0]; } void btree_shift_to_right_child(btree_node *root, int pos, btree_node *y, btree_node *z) { z->num += 1; if(false == z->is_leaf) { z->k[0] = root->k[pos]; root->k[pos] = y->k[y->num-1]; } else { z->k[0] = y->k[y->num-1]; root->k[pos] = y->k[y->num-2]; } for(int i = z->num -1; i > 0; i--) { z->k[i] = z->k[i-1]; } if(false == z->is_leaf) { for(int i = z->num; i > 0; i--) { z->p[i] = z->p[i-1]; } z->p[0] = y->p[y->num]; } y->num -= 1; } void btree_shift_to_left_child(btree_node *root, int pos, btree_node *y, btree_node *z) { y->num += 1; if(false == z->is_leaf) { y->k[y->num-1] = root->k[pos]; root->k[pos] = z->k[0]; } else { y->k[y->num-1] = z->k[0]; root->k[pos] = z->k[0]; } for(int j = 1; j < z->num; j++) { z->k[j-1] = z->k[j]; } if(false == z->is_leaf) { y->p[y->num] = z->p[0]; for(int j = 1; j <= z->num; j++) { z->p[j-1] = z->p[j]; } } z->num -= 1; } void btree_inorder_print(btree_node *root) { if(NULL != root) { btree_inorder_print(root->p[0]); for(int i = 0; i < root->num; i++) { printf("%d ", root->k[i]); btree_inorder_print(root->p[i+1]); } } } void btree_linear_print(btree_node *root) { if(NULL != root) { btree_node *leftmost = root; while(false == leftmost->is_leaf) { leftmost = leftmost->p[0]; } btree_node *iter = leftmost; do { for(int i = 0; i < iter->num; i++) { printf("%d ", iter->k[i]); } iter = iter->next; } while(iter != leftmost); printf("\n"); } } void btree_level_display(btree_node *root) { // just for simplicty, can‘t exceed 200 nodes in the tree btree_node *queue[200] = {NULL}; int front = 0; int rear = 0; queue[rear++] = root; while(front < rear) { btree_node *node = queue[front++]; printf("["); for(int i = 0; i < node->num; i++) { printf("%d ", node->k[i]); } printf("]"); for(int i = 0; i <= node->num; i++) { if(NULL != node->p[i]) { queue[rear++] = node->p[i]; } } } printf("\n"); } int main() { int arr[] = {18, 31, 12, 10, 15, 48, 45, 47, 50, 52, 23, 30, 20}; // int arr[] = {18, 31, 12, 10}; btree_node *root = btree_create(); for(int i = 0; i < sizeof(arr) / sizeof(int); i++) { root = btree_insert(root, arr[i]); btree_level_display(root); btree_linear_print(root); } //int todel[] = {15, 18, 23, 30, 31, 52, 50}; int todel[] = {45, 30, 12, 10}; for(int i = 0; i < sizeof(todel) / sizeof(int); i++) { printf("after delete %d\n", todel[i]); root = btree_delete(root, todel[i]); btree_level_display(root); btree_linear_print(root); } return 0; }
标签:
原文地址:http://www.cnblogs.com/super-d2/p/4868354.html