M阶B树具体实现

B树的代码改改写写,码了很多次 每次都会发现新的问题 也有新的收获

最终终于在2016年的第一天解决了问题

对于高阶(三/四阶以上)的B树其实代码写起来并不麻烦 最麻烦的是3阶B树,也就是2-3树 特别是删除这一块

举个例子 如下图的2-3树 先删除2 得到右图的2-3树

《M阶B树具体实现》 《M阶B树具体实现》

接下来需要调整第二层的结点  用调整2(最下层结点)的方法来调整中间结点是不行的 操作难度也大

所以这里对中间节点的调整应该是这样的

若有左兄弟,则和左兄弟合并。若合并之后的节点关键字数目过大 则分裂这个结点 否则向上递归调整,直至根结点;若没有左兄弟 则对右兄弟做同样的操作。 具体如图:

《M阶B树具体实现》

可见 44 89 98关键字多了 此时就要分裂:

《M阶B树具体实现》

分裂之后向上递归调整 到达根结点 根结点只有一个关键字符合B树特性 故调整结束

完整代码实现如下:

void split(BTree &q, int s, BTree &ap)
{
	int i, j, n = q->keynum;
	ap = (BTNode *)malloc(sizeof(BTNode)); //生成新节点
	ap->ptr[0] = q->ptr[s];
	for (i = s + 1, j = 1; i <= n; i++, j++) {
		ap->key[j] = q->key[i];
		ap->ptr[j] = q->ptr[i];
	}
	ap->keynum = n - s;
	ap->parent = q->parent;
	for (i = 0; i <= ap->keynum; i++) if (ap->ptr[i] != NULL) ap->ptr[i]->parent = ap;
	q->keynum = s - 1;	//保留左侧
}
void successor(BTree &p, int i)
{
	BTree q = p->ptr[i - 1];
	while (q->ptr[q->keynum] != NULL) q = q->ptr[q->keynum];		//取左边最大代替
	p->key[i] = q->key[q->keynum];	//最底层最大和p的第q->keynum个交换 
	p = q;	//替代之后令p指向被替代的位置
}
//p在parent的位置
int findLocation(BTNode *node)
{
	BTree parent = node->parent;
	if (parent == NULL) return -1;
	int loc = 0;
	for (loc = 0; loc <= parent->keynum; loc++) {
		if (parent->ptr[loc] == node) break;	//有点不科学
	}
	return loc;
}
void removeKey(BTree &p, int i)
{
	//只对最下层结点调用
	int n = p->keynum--;
	for (int j = i; j < n; j++) p->key[j] = p->key[j + 1];
}
/*将B树t的第i个关键字K[i]连同第i+1棵子树A[i]合并到第i棵子树A[i-1]中*/
void combineBTNode(BTree &t, int i)
{
	KeyType parentKey;
	BTree lNode;	//左节点
	BTree rNode;	//右节点
	lNode = t->ptr[i - 1];
	rNode = t->ptr[i];
	parentKey = t->key[i];
	++lNode->keynum;
	lNode->key[lNode->keynum] = parentKey;		//先添加双亲节点上的一个关键字
	lNode->ptr[lNode->keynum] = rNode->ptr[0];
	if (rNode->ptr[0] != NULL) rNode->ptr[0]->parent = lNode;
	for (int k = 1; k <= rNode->keynum; k++) {	//添加rNode的所有关键字
		++lNode->keynum;
		lNode->key[lNode->keynum] = rNode->key[k];
		lNode->ptr[lNode->keynum] = rNode->ptr[k];	//复制指针 adjustTopNode用到
		if (rNode->ptr[k] != NULL)  rNode->ptr[k]->parent = lNode;	//修改双亲结点
	}
	//移除t的关键字Ki和指向p的指针Ai
	for (int j = i; j < t->keynum; j++) {
		t->key[j] = t->key[j + 1];
		t->ptr[j] = t->ptr[j + 1];
	}
	t->keynum--;	//双亲结点数-1
}
//调整中间结点p
void adjustTopNode(BTree &root, BTree &p)
{
	//上层节点调整策略:合并
	BTree parent = p->parent;
	int pos;	//合并之后的位置
	if (parent == NULL) {
		if (p->keynum == 0) {
			root = root->ptr[0];
			root->parent = NULL;
		}
		return;
	}
	int i = findLocation(p);
	int n = parent->keynum;
	if (i + 1 <= n) pos = i + 1;
	else pos = i;
	combineBTNode(parent, pos);
	//检查合并点
	BTree q = parent->ptr[pos - 1];
	if (q->keynum >= M) {
		BTree ap;
		int s = (q->keynum + 1) / 2;
		KeyType midKey = q->key[s];
		split(q, s, ap);
		for (int j = parent->keynum; j > pos; j--) {
			parent->ptr[j] = parent->ptr[j - 1];
			parent->key[j] = parent->key[j - 1];
		}
		parent->ptr[pos] = ap;
		parent->key[pos] = midKey;
		parent->keynum++;
	}
	//检查双亲结点
	if (parent->keynum < (M + 1) / 2 - 1) adjustTopNode(root, parent);	//递归调整
}
//调整最下层结点p
void adjustLowestNode(BTree &root, BTree &p)
{
	BTree parent = p->parent;	//parent非空
	if (parent == NULL) return;
	int i = findLocation(p);
	int n = parent->keynum;
	BTree brother;
	KeyType parentKey;
	/*右兄弟存在且关键字数目大于[m/2]-1*/
	if (i + 1 <= n && parent->ptr[i + 1]->keynum > (M + 1) / 2 - 1) {
		brother = parent->ptr[i + 1];	//右兄弟
		parentKey = parent->key[i + 1];
		parent->key[i + 1] = brother->key[1];	//第一个(最小)关键字上移
		p->key[++p->keynum] = parentKey;	//parentKey下移 肯定是最大 指针本来就为NULL无需调整
		removeKey(brother, 1);	//移去brother的最小关键字
	}
	/*左兄弟存在且关键字数目大于[m/2]-1*/
	else if (i - 1 >= 0 && parent->ptr[i - 1]->keynum > (M + 1) / 2 - 1) {
		brother = parent->ptr[i - 1];	//左兄弟
		parentKey = parent->key[i];
		parent->key[i] = brother->key[brother->keynum];	//最后一个(最大)关键字上移
		for (int j = p->keynum; j > 0; j--) p->key[j + 1] = p->key[j];
		p->key[1] = parentKey;
		++p->keynum;
		removeKey(brother, brother->keynum);
	}
	/*没有富余结点 进行合并*/
	else {
		if (i + 1 <= n) combineBTNode(parent, i + 1);	//合并右兄弟
		else combineBTNode(parent, i);	//合并左兄弟
		//检查双亲结点
		if (parent->keynum < (M + 1) / 2 - 1) adjustTopNode(root, parent);
	}
}
/*删除B树root的子树p的关键字K[i]*/
void deleteKey(BTree &root, BTree &p, int i)
{
	if (p->ptr[i - 1] != NULL) {		//not last level
		successor(p, i);
		deleteKey(root, p, p->keynum);
	}
	else {
		removeKey(p, i);
		if (p->keynum < (M + 1) / 2 - 1)		//删除之后关键字个数小于(m-1)/2
			adjustLowestNode(root, p);
	}
}
/*删除函数
 * @param t B树
 * @param key 删除关键字
 * @return Status类型数据
 * 成功返回OK 失败返回ERROR
 * @user ChenJunhan 2015-12
 */
Status deleteBTree(BTree &t, KeyType key)
{
	Result r;
	r = searchBTree(t, key);
	if (r.tag == 0) return ERROR;
	else deleteKey(t, r.pt, r.pos);
	return OK;
}

    原文作者:B树
    原文地址: https://blog.csdn.net/stranger_cjhan/article/details/50277367
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞