注:B+树叶子节点的概念又恢复为了最后一个节点是叶子节点,其他都是非叶子节点
B树:节点中存放关键字和数据指针(外存地址)

为了使得树变得更矮,
就要想办法在一个节点中存放更多的数据---非叶子节点中只存放关键字,不再跟着数据指针
叶子节点中关键字和数据指针一起放,并且上层节点中的数据 只是下层节点数据的索引,数据地址都在叶子节点中找

m阶B+树的性质:
1.非叶子节点中只存放关键字,不再跟着数据指针
叶子节点中关键字和数据指针一起放,并且上层节点中的数据 只是下层节点数据的索引,数据地址都在叶子节点中找
2.B+树中 关键字的个数和孩子节点的个数相同(代码里面下标可以一一对应)
因为父亲中的每一个关键字都会作为孩子的索引--->作为孩子节点的最大值
3.B+树有两个阶 分别控制非叶子节点和叶子节点。 但是考研统一 m阶B+树
毕竟一个指针存放节点地址,一个存放外存地址,还需要一个标志来区分它俩
4.查找操作一定要查找叶子节点上(复杂度恒为logn )
5.叶子节点之间通过next指针相连,类似链表---->方便区间查找

比如查找15,80是否存在:对15进行一次单点查找,然后就从叶子节点15开始继续往后遍历
6.每个非叶子节点最多有m棵子树,最多m个关键字
7.非叶 根节点最少有两颗子树, 其他内部节点至少有ceil(m/2)棵子树

总结优势:
1.同样大小的节点,B+树存放的关键字更多,阶更大,相同的数据量时,建立的B+树要比B树矮得多,查找更快
2.B+树的叶子节点之间通过指针相连,支持区间查找和顺序查找
B+树的操作:
0.建树: 节点结构体,B+树结构体,结果结构体
可参考

typedef int KEY; //关键字类型 typedef int VALUE;//真实数据类型
1.单点查找:和B树的查找一样,只不过到叶子节点才可以停
2.区间查找: 先对左端点进行单点查找,然后顺着叶子节点进行顺序查找即可
3.插入数据k: 和B树的插入的步骤基本一样:先查找到位置<节点位置,下标位置>,然后插入,向上调整
- 分裂是分两半(B树分三部分) 并把每部分的最大值复制到父节点

- 向上调整的过程中根节点超出上限了:除了分裂,新添加一个根节点
- 叶子节点的分裂需要维护next指针
- 如果插入的是最大值(比叶子节点最右边的数据还大),要向上修改祖先们的节点中的关键字
(为了避免插入最大值时向上修改关键字,在具体实现B+树时,可以不存最大孩子的索引)

理论上孩子数=关键字数,但是实践过程中可以变化
4.删除操作:和B树一样。兄弟够借就借,不够借就合并。
直到不低于下限或者到根节点,孩子合并之后根节点只有一个关键字,删掉根节点。 结束

代码实现:
cpp
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define item_cmp(a,b) ((a) - (b))
/********************B+树的代码实现****************************/
typedef int KEY;
typedef int VALUE;
typedef struct bplus_node_s* bplus_node_pt;
//B+树节点的定义
typedef struct bplus_node_s {
KEY* keys;//主键 最大max个 最小min个
VALUE* data;//真实数据 最大max个 最小min个 对于内部结点 data是NULL
bplus_node_pt* child;//子节点 最大max+1个 最小min+1个
bplus_node_pt next;//指向兄弟结点 仅仅是叶子结点的时候才有值
int keynum;//当前元素个数
bplus_node_pt parent;
}bplus_node_t;
typedef struct bplus_tree_s* bplus_tree_pt;
//B+树的定义
typedef struct bplus_tree_s {
bplus_node_pt root;
int max;
int min;
}bplus_tree_t;
/******************************函数声明**************************************/
int bplus_tree_create(bplus_tree_pt* _tree, int m);//B+树的创建
int bplus_tree_insert(bplus_tree_pt tree, KEY key, VALUE value);
int binary_search(KEY* keys, KEY key, int left, int right, int* index);
bplus_node_pt bplus_node_new_leaf(int m);
int _bplus_tree_insert(bplus_tree_pt tree, bplus_node_pt node, KEY key, VALUE value);
bplus_node_pt bplus_node_new_internal(int m);
void bplus_tree_printf(bplus_tree_pt tree);
void bplus_node_show(bplus_node_pt node, int h);
void bplus_node_printfnode(KEY* key, int h);
void bplus_tree_delete(bplus_tree_pt tree, KEY key);
/******************************函数实现**************************************/
int bplus_tree_create(bplus_tree_pt* _tree, int m)
{
bplus_tree_pt tree = (bplus_tree_pt)malloc(sizeof(bplus_tree_t));
if (tree == NULL)
{
return 0;
}
tree->root = NULL;
tree->max = m;
tree->min = m / 2;
*_tree = tree;
return 1;
}
/*
二分查找 找到数组中指定的key的位置 如果存在返回1 否则返回0
如果找到索引为该值的位置 否则返回右邻的值的位置(child的位置)
*/
int binary_search(KEY* keys, KEY key, int left, int right, int* index)
{
int mid;
while (left <= right)
{
mid = (left + right) / 2;
if (item_cmp(keys[mid],key) > 0)
{
right = mid - 1;
}
else if (item_cmp(keys[mid], key) < 0)
{
left = mid + 1;
}
else
{
*index = mid;
return 1;
}
}
*index = left;
return 0;
}
/*
创建新的叶子结点
*/
bplus_node_pt bplus_node_new_leaf(int m)
{
bplus_node_pt node = (bplus_node_pt)malloc(sizeof(bplus_node_t));
if (node == NULL)
{
return NULL;
}
node->parent = NULL;
node->next = NULL;
node->keynum = 0;
node->keys = (KEY*)malloc(sizeof(KEY) * (m + 1));
node->data = (VALUE*)malloc(sizeof(VALUE) * (m + 1));
if (node->keys == NULL || node->data == NULL)
{
free(node->keys);
free(node->data);
free(node);
return NULL;
}
node->child = NULL;
return node;
}
/*
创建新的内部结点
*/
bplus_node_pt bplus_node_new_internal(int m)
{
bplus_node_pt node = (bplus_node_pt)malloc(sizeof(bplus_node_t));
if (node == NULL)
{
return NULL;
}
node->parent = NULL;
node->next = NULL;
node->keynum = 0;
node->keys = (KEY*)malloc(sizeof(KEY) * (m + 1));
node->data = NULL;
node->child = (bplus_node_pt*)malloc(sizeof(bplus_node_pt)*(m + 2));;
if (node->keys == NULL || node->child == NULL)
{
free(node->keys);
free(node->child);
free(node);
return NULL;
}
return node;
}
/*
元素的插入以及分裂操作
*/
int _bplus_tree_insert(bplus_tree_pt tree, bplus_node_pt node, KEY key, VALUE value)
{
bplus_node_pt parent ,node2;
int mid;
KEY temp;
int i;
/*先插入叶子结点*/
for (i = node->keynum; i > 0 && item_cmp(node->keys[i - 1],key) > 0; i--)
{
node->keys[i] = node->keys[i - 1];
node->data[i] = node->data[i - 1];
}
node->keys[i] = key;
node->data[i] = value;
node->keynum++;
while (node->keynum > tree->max)
{
/*分裂结点*/
if (node->child == NULL)
{
//叶子结点分裂
node2 = bplus_node_new_leaf(tree->max);
}
else {
//内部结点分裂
node2 = bplus_node_new_internal (tree->max);
}
if (node2 == NULL)
{
return 0;
}
//拷贝数据
mid = node->keynum / 2;
temp = node->keys[mid];
if (node->child == NULL)
{
node2->keynum = node->keynum - mid;
memcpy(node2->keys, node->keys + mid, sizeof(KEY) * (node2->keynum));
memcpy(node2->data, node->data + mid, sizeof(KEY) * (node2->keynum));
node2->next = node->next;
node->next = node2;
}
else
{
node2->keynum = node->keynum - mid - 1;
memcpy(node2->keys, node->keys + mid + 1, sizeof(KEY) * (node2->keynum));
memcpy(node2->child, node->child + mid + 1, sizeof(bplus_node_pt) * (node->keynum - mid));
//重新设置父指针
for (int i = 0; i <= node2->keynum; i++)
{
node2->child[i]->parent = node2;
}
}
node->keynum = mid;
/*插入父节点*/
parent = node->parent;
if (parent == NULL)
{
//生成一个新的根节点
parent = bplus_node_new_internal(tree->max);
if (parent == NULL)
{
return 0;
}
parent->child[0] = node;
node->parent = parent;
tree->root = parent;
}
/*增加数据 右子树*/
for (i = parent->keynum; i > 0 && item_cmp(parent->keys[i - 1], temp) > 0; i--)
{
parent->keys[i] = parent->keys[i - 1];
parent->child[i + 1] = parent->child[i];
}
parent->keys[i] = temp;
parent->child[i + 1] = node2;
parent->keynum++;
node2->parent = parent;
//回溯 向上继续判断
node = parent;
}
return 1;
}
int bplus_tree_insert(bplus_tree_pt tree, KEY key, VALUE value)
{
bplus_node_pt node;
int ret,index;
if (tree->root == NULL)
{
node = bplus_node_new_leaf(tree->max);
if (node == NULL)
{
return 0;
}
tree->root = node;
}
node = tree->root;
//查找叶子结点
while (node->child != NULL)
{
ret = binary_search(node->keys, key, 0, node->keynum - 1, &index);
if (ret == 1)
{
index++;
}
node = node->child[index];
}
ret = binary_search(node->keys, key, 0, node->keynum - 1, &index);
if (ret == 1)
{
//这个结点已经存在了
return 0;
}
_bplus_tree_insert(tree, node, key, value);
return 1;
}
void bplus_node_printfnode(KEY* key, int h)
{
for (int i = 0; i < h; i++)
{
printf(" ");
}
if (key == NULL)
{
printf("\n");
}
else {
printf("%d\n", *key);
}
}
void bplus_node_show(bplus_node_pt node, int h)
{
if (node == NULL)
{
return;
}
if (node->child != NULL)
{
bplus_node_show(node->child[0], h + 1);
}
for (int i = 0; i < node->keynum; i++)
{
bplus_node_printfnode(&node->keys[i], h);
if (node->child != NULL)
{
bplus_node_show(node->child[i + 1], h + 1);
}
}
}
void bplus_tree_printf(bplus_tree_pt tree)
{
bplus_node_show(tree->root, 0);
}
/*
叶子结点的左旋转 把右节点的第一个值移到左节点
*/
void _bplus_leaf_left_rotate(bplus_node_pt node,int index)
{
bplus_node_pt left, right;
left = node->child[index];
right = node->child[index + 1];
left->keys[left->keynum] = right->keys[0];
left->data[left->keynum] = right->data[0];
left->keynum++;
//对右节点进行移位
for (int i = 0; i < right->keynum - 1; i++)
{
right->keys[i] = right->keys[i + 1];
right->data[i] = right->data[i + 1];
}
right->keynum--;
node->keys[index] = right->keys[0];
}
/*
内部结点的左旋转 把右节点的第一个值移到父节点 父节点对应的值移到左节点
*/
void _bplus_internal_left_rotate(bplus_node_pt node, int index)
{
bplus_node_pt left, right;
left = node->child[index];
right = node->child[index + 1];
left->keys[left->keynum] = node->keys[index];
left->child[left->keynum + 1] = right->child[0];
left->keynum++;
node->keys[index] = right->keys[0];
//对右节点进行移位
for (int i = 0; i < right->keynum - 1; i++)
{
right->keys[i] = right->keys[i + 1];
}
for (int i = 0; i < right->keynum; i++)
{
right->child[i] = right->child[i + 1];
}
right->keynum--;
}
/*
合并结点元素的左右两个子节点
*/
void _bplus_node_merge(bplus_node_pt node, int index)
{
bplus_node_pt left, right;
left = node->child[index];
right = node->child[index + 1];
if (left->child != NULL)
{
/*修改左子节点*/
left->keys[left->keynum] = node->keys[index];
memcpy(left->keys + left->keynum + 1, right->keys, sizeof(KEY) * (right->keynum));
for (int i = 0; i <= right->keynum; i++)
{
right->child[i]->parent = left;
left->child[left->keynum + i + 1] = right->child[i];
}
left->keynum = left->keynum + right->keynum + 1;
}
else
{
memcpy(left->keys + left->keynum, right->keys, sizeof(KEY) * (right->keynum));
memcpy(left->data + left->keynum, right->data, sizeof(VALUE) * (right->keynum));
left->keynum = left->keynum + right->keynum;;
}
/*修改父节点*/
for (int i = index; i < node->keynum - 1; i++)
{
node->keys[i] = node->keys[i + 1];
}
for (int i = index + 1; i < node->keynum; i++)
{
node->child[i] = node->child[i + 1];
}
node->keynum--;
/*释放右节点*/
free(right->keys);
free(right->data);
free(right->child);
free(right);
}
/*
叶子结点的右旋转
*/
void _bplus_leaf_right_rotate(bplus_node_pt node, int index)
{
bplus_node_pt left, right;
left = node->child[index];
right = node->child[index + 1];
for (int i = right->keynum; i > 0; i--)
{
right->keys[i] = right->keys[i - 1];
right->data[i] = right->data[i - 1];
}
right->keynum++;
right->keys[0] = left->keys[left->keynum - 1];
right->data[0] = left->data[left->keynum - 1];
left->keynum--;
node->keys[index] = right->keys[0];
}
/*
内部结点的右旋转 左节点的最后一个值到父节点 父节点对应的值到右节点
*/
void _bplus_internal_right_rotate(bplus_node_pt node, int index)
{
bplus_node_pt left, right;
left = node->child[index];
right = node->child[index + 1];
for (int i = right->keynum; i > 0; i--)
{
right->keys[i] = right->keys[i - 1];
}
right->keys[0] = node->keys[index];
for (int i = right->keynum + 1; i > 0; i--)
{
right->child[i] = right->child[i - 1];
}
right->child[0] = left->child[left->keynum];
right->keynum++;
node->keys[index] = left->keys[left->keynum - 1];
left->keynum--;
}
void _bplus_tree_delete(bplus_tree_pt tree, bplus_node_pt node, int index)
{
bplus_node_pt parent, sibling;
/*先删除叶子结点的指定的值*/
for (int i = index; i < node->keynum - 1; i++)
{
node->keys[i] = node->keys[i + 1];
node->data[i] = node->data[i + 1];
}
node->keynum--;
parent = node->parent;
while (node->keynum < tree->min && parent!= NULL)
{
/*寻找到当前结点在父节点当中的位置*/
for ( index = 0; index <= parent->keynum && parent->child[index] != node; index++);
if (index > parent->keynum)
{
//在他的父节点中没找到这个孩子
return;
}
if (index == 0)
{
//如果是第一个结点 没有左兄弟 只有右兄弟
sibling = parent->child[1];
if (sibling->keynum > tree->min)
{
//迁移数据
if (node->child == NULL)
{
//叶子结点的迁移
_bplus_leaf_left_rotate(parent, 0);
}
else {
_bplus_internal_left_rotate(parent, 0);
}
}
else
{
/*合并兄弟*/
_bplus_node_merge(parent, 0);
}
}
else
{
/*
如果结点是父节中的第index个子节点,兄弟是第index - 1
中间的分割元素是父节点中的第index - 1个元素
*/
sibling = parent->child[index - 1];
if (sibling->keynum > tree->min)
{
//从左兄弟迁移数据
if (node->child == NULL)
{
//叶子结点的右旋转
_bplus_leaf_right_rotate(parent, index - 1);
}
else {
//内部结点的右旋转
_bplus_internal_right_rotate(parent, index - 1);
}
}
else
{
/*合并兄弟*/
_bplus_node_merge(parent, index - 1);
}
}
node = parent;
parent = node->parent;
}
if (tree->root->keynum == 0 && tree->root->child != NULL)
{
node = tree->root;
tree->root = node->child[0];
free(node->keys);
free(node->data);
free(node->child);
free(node);
}
}
void bplus_tree_delete(bplus_tree_pt tree, KEY key)
{
bplus_node_pt node = tree->root;
int ret = 0, index;
/*先查找到叶子*/
while (node->child != NULL)
{
ret = binary_search(node->keys, key, 0, node->keynum - 1, &index);
if (ret == 1)
{
index++;
}
node = node->child[index];
}
ret = binary_search(node->keys, key, 0, node->keynum - 1, &index);
if (ret == 0)
{
return;
}
_bplus_tree_delete(tree,node,index);
return;
}
int main()
{
bplus_tree_pt tree;
int ret;
ret = bplus_tree_create(&tree, 5);
for (int i = 0; i < 30; i++)
{
bplus_tree_insert(tree, i, 1);
}
bplus_tree_printf(tree);
printf("\n删除元素\n");
bplus_tree_delete(tree, 1);
bplus_tree_delete(tree, 2);
bplus_tree_delete(tree, 3);
bplus_tree_delete(tree, 4);
bplus_tree_delete(tree, 5);
bplus_tree_delete(tree,6);
bplus_tree_delete(tree, 7);
bplus_tree_delete(tree, 8);
bplus_tree_delete(tree, 9);
bplus_tree_delete(tree, 10);
bplus_tree_delete(tree, 11);
bplus_tree_delete(tree, 12);
bplus_tree_delete(tree, 26);
bplus_tree_delete(tree, 25);
bplus_tree_delete(tree, 23);
bplus_tree_printf(tree);
}