Linux+C/C++ 服务器之B树

B树可以是多叉树多叉树不一定是多叉树

多叉树和b树的差别

多叉树说明树的结构有多个叉,而B树的所有叶子节点在同一层.

B树的性质:

 

 B树的层高:

        

 

B树

B树的所有结点都存储数据 内存寻址用红黑和B  

B+树

B+树的内结点不存储数据,仅作索引;所有数据都是存储在叶子结点上。 而B树的所有结点都是存储数据的。 B+树更适合做磁盘索引,性能优于B树;因为B+的内结点不存储数据。 磁盘寻址用B+ 更适合做磁盘索引,内节点就是非叶子节点,右子节点

B树的节点定义:
typedef int KEY_VALUE;

//n+1叉树 key = n个
typedef struct _btree_node {
	KEY_VALUE *keys;     //n个
	struct _btree_node **childrens; //分n+1叉
	int num;   //判断节点中存储了多少个数据
	int leaf;  //判断是否是叶子节点 
} btree_node;
B树的根节点定义:
typedef struct _btree {
	btree_node *root;
	int t;
} btree;
B树的添加

根节点分叉

key为奇数 分叉数量/子树数量是偶数   key为奇数是为了方便分裂的时候将中间节点提出

当满足子节点到五个时 开始分裂将中间的F放到和C并列

注意:是先分裂再添加这样不影响性质

 一直添加到根节点也满足5

 

 每次添加叶子节点 如何满足最大值之后下一次添加将中间的节点提拔为父节点 以此往复

B树的叶子节点删除

 在添加完全的基础上进行删除

先查找 查找的时间复杂度是log n(m/n)

合并删除 

先找到A 不能直接删因为会违背性质 因为A小于C所以合并C两侧的子树进行删除

 合并后借位分裂

只能从父节点借位  借不到就采用合并删除

问题:在什么时候需要借位

两边子树节点数量不平衡

如果子树的数量 = m/2 -1 这时候就需要借位 避免之后资源不足

 总结:对于B树的删除操作先通过合并或者借位使得B树能够达到删除的状态再进行删除操作

 需要子树数量满足M/2 - 1 > 2  才能删除

 B树的内节点删除

先借位然后合并将内节点变为叶子节点之后删除

代码实现
创建树
btree_node *btree_create_node(int t, int leaf) {

	btree_node *node = (btree_node*)calloc(1, sizeof(btree_node));
	if (node == NULL) assert(0);

	node->leaf = leaf;
	node->keys = (KEY_VALUE*)calloc(1, (2*t-1)*sizeof(KEY_VALUE));   //calloc是自动清0 malloc需要手动清空
	node->childrens = (btree_node**)calloc(1, (2*t) * sizeof(btree_node*));
	node->num = 0;

	return node;
}
删除树
void btree_destroy_node(btree_node *node) {

	assert(node);

	free(node->childrens);
	free(node->keys);
	free(node);
	
}
分裂操作

//第一个参数是树,第二个参数是分裂的哪个节点,第三个参数是从第几个开始分
void btree_split_child(btree *T, btree_node *x, int i) {
	int t = T->t;

	btree_node *y = x->childrens[i];
	btree_node *z = btree_create_node(t, y->leaf);

	z->num = t - 1;

	int j = 0;
	for (j = 0;j < t-1;j ++) {
		z->keys[j] = y->keys[j+t];
	}
	if (y->leaf == 0) { //内节点
		for (j = 0;j < t;j ++) {
			z->childrens[j] = y->childrens[j+t];
		}
	}

	y->num = t - 1;
	//提拔x为内节点 将x插到中间 
	for (j = x->num;j >= i+1;j --) {
		x->childrens[j+1] = x->childrens[j];
	}

	x->childrens[i+1] = z;
	//对x的key进行交换
	for (j = x->num-1;j >= i;j --) {
		x->keys[j+1] = x->keys[j];
	}
	x->keys[i] = y->keys[t-1];
	x->num += 1;
	
}
添加节点

创建空的节点然后指向

void btree_insert(btree *T, KEY_VALUE key) {
	//int t = T->t;

	btree_node *r = T->root;
	if (r->num == 2 * T->t - 1) {
		
		btree_node *node = btree_create_node(T->t, 0);
		T->root = node;

		node->childrens[0] = r;

		btree_split_child(T, node, 0);

		int i = 0;
		if (node->keys[0] < key) i++;
		btree_insert_nonfull(T, node->childrens[i], key);
		
	} else {
		btree_insert_nonfull(T, r, key);
	}
}
合并

//{child[idx], key[idx], child[idx+1]} 
void btree_merge(btree *T, btree_node *node, int idx) {

	btree_node *left = node->childrens[idx];
	btree_node *right = node->childrens[idx+1];

	int i = 0;

	/data merge
	left->keys[T->t-1] = node->keys[idx];
	for (i = 0;i < T->t-1;i ++) {
		left->keys[T->t+i] = right->keys[i];
	}
	if (!left->leaf) {
		for (i = 0;i < T->t;i ++) {
			left->childrens[T->t+i] = right->childrens[i];
		}
	}
	left->num += T->t;

	//destroy right
	btree_destroy_node(right);

	//node 
	for (i = idx+1;i < node->num;i ++) {
		node->keys[i-1] = node->keys[i];
		node->childrens[i] = node->childrens[i+1];
	}
	node->childrens[i+1] = NULL;
	node->num -= 1;

	if (node->num == 0) {
		T->root = left;
		btree_destroy_node(node);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值