根据算法导论的描述。B树是一种特殊的平衡树和查找树。其主要用于磁盘内数据的存储和查找。因此,B树一般每个结点会比较大,包含许多数据关键字,最好占一个页面(page),这样存取的时候直接存取一个结点的数据。
B树的基本性质(M阶):
1、B树的每个叶子节点的高度均一致。
2、对于非空B树,普通非根非叶节点至少有M-1个关键字(M个子女),至多2M-1个关键字(2M个子女)。根节点至少包含2个子女(因为根节点只有1个关键字时,要有两个对应的孩子指针)。
3、结点内部的数据关键字是按从小到大排序的。
B树的结点的结构(M阶):
typedef struct btree_node
{
int k[2*M-1]; //用于存储数据关键字
btree_node *p[2*M]; //用于存储指向孩子的指针
int num; // 当前结点内数据关键字的个数, <=2*M-1
bool is_leaf; // 当前结点是否是叶子结点 true/false
}btree_node,*btree;
B树操作上的特质:
1、插入新数据关键字总是要往叶子结点上插入。
2、插入操作所造成的B树的扩张,使得树的高度升高一定是在根节点增加高度的。(这是由插入操作的手段所决定。)
B树结点的创建:
btree init_btree_node() { btree_node *node = (btree_node*)malloc(sizeof(btree_node)); if(node ==NULL) 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; return node; }
//child结点满了,一分为二: 0~M-2 M-1 M~2M-2 // 1 //M-1 M-1 int split_child(btree parent, int pos, btree child) { //create a new child node for the other M-1 keys btree_node *new_child = init_btree_node(); if(new_child == NULL) 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(new_child->is_leaf == false) for(int i=0;i<M;i++) new_child->p[i] = child->p[i+M]; //adjust the former child node child->num = M-1; //adjust parent node 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 ++; return 1; }
--对根节点执行btree_insert();
--如果根节点满了,B树需要升高一层;
--向其孩子结点插入,遇到满结点需要分裂,逐步递归到叶子结点。
btree btree_insert(btree root, int target) { if(root == NULL) return NULL; if(root->num == 2*M-1) { //create new root //the only way to add the height of btree btree_node *node = init_btree_node(); if(node == NULL) return NULL; node->is_leaf = false; node->p[0] = root; split_child(node, 0, root); btree_insert_nonfull(node, target); return node; } else { btree_insert_nonfull(root, target); return root; } } void btree_insert_nonfull(btree node, int target) { if(node->is_leaf == true) { 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 ++; } else { int pos = node->num; while(pos>0 && target < node->k[pos-1]) pos--; if(node->p[pos]->num == 2*M-1) { split_child(node, pos, node->p[pos]); if(target > node->k[pos]) pos++; } btree_insert_nonfull(node->p[pos], target); } }
未完成,有待学习。