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树特性 故调整结束
完整代码实现如下:
最终终于在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; }
相关文章推荐
- 使用了非标准扩展:“xxx”使用 SEH,并且“xxx”有析构函数
- 篮桥杯入门训练 圆的面积
- 农行网银软件导致XP死机
- Lua语言教程0 ——编译环境搭建
- [javase学习笔记]-3.2 switch语句
- 【NuGet】远程服务器返回错误:<403>已禁止
- 链表的基本功能实现
- jwt(json-web-token)在rest中的实现--jersey
- linux内存泄漏检测
- APUE:实际用户ID和有效用户ID(euid)
- 推荐几篇学习rest风格的文章
- Mantle源代码阅读笔记 一
- (Fun)*((int*)*(int*)(&b)); http://bbs.csdn.net/topics/320008423
- 20151212jquery学习笔记--工具函数
- codeforces 418 C Square Table (随机算法)
- SAX解析XML文件
- VS2013下 开发简单的MFC小程序
- linux C 学习---函数指针
- JavaScript、CSS、HTML 实现用户注册页面与信息校验
- Tomcat 源码分析(转)