您的位置:首页 > 其它

M阶B树具体实现

2015-12-12 19:50 351 查看
B树的代码改改写写,码了很多次 每次都会发现新的问题 也有新的收获

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

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

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





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

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

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



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



分裂之后向上递归调整 到达根结点 根结点只有一个关键字符合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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: