B+树实现
2016-05-22 19:59
351 查看
最近花了很长时间写了b和b+的实现,由于第一次写,写的时候浪费了很多时间,但是多写两次就能很快写出来了,且思路也清晰了。
先来b+树
树的实现起来比较麻烦就是插入和删除了,因为这两个都不是简单的就能够完成的所以需要进行准备很多辅助函数。
对于插入,当树需要调整,要分清需要创建什么类型的节点,是分支还是叶子,需要考虑的也就是空树的时的插入,只有根节点时的插入,以及当需要分裂时是要考虑到层层向上分裂。由于会产生新根所以要注意调整,另外我最大的错误就是经常忘记在移动孩子节点时忘记修改parent,因此调了很长时间才意识到。
当删除时,要区分叶子和分支的删除。。删除时一定是在叶子上进行删除的,所以当删除时如果树不平衡会出现借元素,合并叶子元素等情况。
而叶子的合并又会导致分支中的元素减少(我并没有采用有些方法中保留索引关键字,如果叶子中的元素也是分支的索引关键字我是一起都删掉了的。)分支中元素的减少又会产生分支的借元素和合并分支,也是要进行考虑。
先来b+树
#include<stdio.h> #include<stdlib.h> #include<string.h> const int maxsize = 5;//定义b+树的阶数 const int maxelem = maxsize-1;//非叶节点元素的最大数 const int minsize = maxsize / 2;//非叶节点元素最小个数 const int leafmax = maxsize; const int leafmin = maxsize / 2 + 1; typedef enum elemtype { Leaf, Brch }elemtype;//定义节点类型 typedef struct bplus_treenode { char data[maxsize + 1]; struct bplus_treenode *parent; union { struct bplus_treenode *sub[maxsize + 1]; struct { char *p[maxsize + 1]; struct bplus_treenode *next; struct bplus_treenode *front; }; }; elemtype nodetype; int num; }node;//定义树的节点 typedef struct bptree { node* root; node* first; }Bptree; typedef struct Result { node * pnode; int pos; bool tag; }Result;//用来存放查找结果 node * buyleaf() { node * ret = (node*)malloc(sizeof(node)); ret->num = 0; ret->nodetype = Leaf; ret->parent = NULL; ret->next = ret->front = NULL; memset(ret->sub, NULL, sizeof(node*)*(maxsize + 1)); return ret; } node * buybrch() { node * ret = (node*)malloc(sizeof(node)); ret->nodetype = Brch; ret->parent = NULL; memset(ret->sub, 0, sizeof(node*)*(maxsize + 1)); ret->next = ret->front = NULL; ret->num = 0; return ret; } Result find(node * root, char key) { node * ptr = root; Result res = { NULL,0,false }; if (root == NULL) return res; while (ptr != NULL && ptr->nodetype != Leaf) { int i = ptr->num; for (; i > 0 && key < ptr->data[i]; i--) {} res.pnode = ptr; res.pos = i; ptr = ptr->sub[i]; } if (ptr != NULL) { int i = ptr->num - 1; for (; i >= 0 && key < ptr->data[i]; i--) {} res.pnode = ptr; res.pos = i; if (ptr->data[i] == key) { res.tag = true; } } return res; } node * makeroot(char key, char *p) { node * root = (node*)malloc(sizeof(node)); root->data[0] = key; memset(root->sub, NULL, sizeof(node*)*maxsize + 1); root->p[0] = p; root->num = 1; root->parent = NULL; root->nodetype = Leaf; root->next = root->front = NULL; return root; } void insert_leaf(node *ptr, int pos, char key, char *record) { int i = ptr->num; for (; i - 1 > pos; --i) { ptr->data[i] = ptr->data[i - 1]; ptr->p[i] = ptr->p[i - 1]; } ptr->data[i] = key; ptr->p[i] = record; ptr->num++; } //从sourc中pos位置之后移动数据到des中 void move_leaf(node * sourc, node *des, int pos) { int i = pos + 1; for (int j = 0; i < sourc->num; j++, i++) { des->data[j] = sourc->data[i]; des->p[j] = sourc->p[i]; sourc->p[i] = NULL; } des->num = sourc->num = leafmin; } void move_brch(node * sourc, node * des, int pos) { int i = pos + 1; for (int j = 0; i <= sourc->num; j++, i++) { des->data[j] = sourc->data[i]; des->sub[j] = sourc->sub[i]; des->sub[j]->parent = des; sourc->sub[i] = NULL; } des->num = sourc->num = minsize; } void insert_brch(node *ptr, int pos, char kx, node *right) { int i = ++ptr->num; for (; i - 1 > pos; --i) { ptr->data[i] = ptr->data[i - 1]; ptr->sub[i] = ptr->sub[i - 1]; } ptr->data[i] = kx; ptr->sub[i] = right; if (right != NULL) { right->parent = ptr; } } node * adjust(node * ptr) {//插入时的调整 node * par = ptr->parent; node * newnode = NULL; if (ptr->nodetype == Leaf) { newnode = buyleaf(); newnode->next = ptr->next; ptr->next = newnode; newnode->front = ptr; if (newnode->next != NULL) newnode->next->front = newnode; } else newnode = buybrch(); if (newnode->nodetype == Leaf) move_leaf(ptr, newnode, leafmin - 1); else move_brch(ptr, newnode, minsize); if (par == NULL) { node * newroot = buybrch(); newroot->sub[0] = ptr; newroot->sub[1] = newnode; newroot->data[1] = newnode->data[0]; newnode->parent = newroot; ptr->parent = newroot; newroot->num++; return newroot; } else { int pos = par->num; for (; pos > 0 && ptr != par->sub[pos]; --pos) {} insert_brch(par, pos, newnode->data[0], newnode); if (par->num > maxelem) { return adjust(p ea90 ar); } } return NULL; } void insert(node * &ptr, char key, char *reco) { if (ptr == NULL) { ptr = makeroot(key, reco); return; } Result res = find(ptr, key); if (res.tag == true) return; else { node * pnode = res.pnode; unsigned pos = res.pos; node *par = pnode->parent; insert_leaf(pnode, pos, key, reco); if (pnode->num > leafmax) { node * temp = adjust(pnode); if (temp != NULL) ptr = temp; } } } node * set_first(node *root) { node * first = NULL; while (root != NULL && root->nodetype != Leaf) { first = root; root = root->sub[0]; } if (root->nodetype == Leaf) return root; return first; } void dele_brch(node * ptr, int pos) { int i = pos; for (; i < ptr->num; ++i) { ptr->data[i] = ptr->data[i + 1]; ptr->sub[i] = ptr->sub[i + 1]; } --ptr->num; } void merge_lebrch(node * left, node *&ptr, node *par, int parpos) { int i = ++left->num; ptr->data[0] = par->data[parpos]; for (int j = 0; j < ptr->num; ++j, ++i) { left->data[i] = ptr->data[j]; left->sub[i] = ptr->sub[j]; ptr->sub[j]->parent = left; } left->num += ptr->num; free(ptr); dele_brch(par, parpos); ptr = left; } void merge_leaf(node * des, node* &sorc, node *par, int parpos) { int i = des->num; for (int j = 0; j < sorc->num; ++j, ++i) { des->data[i] = sorc->data[j]; des->p[i] = sorc->p[j]; } des->num += sorc->num; free(sorc); dele_brch(par, parpos); sorc = des; } void dele_leaf(node *ptr, int pos, int parpos) { --ptr->num; for (int i = pos; i < ptr->num; ++i) { ptr->data[i] = ptr->data[i+1]; ptr->p[i] = ptr->p[i+1]; } if (pos == 0) { ptr->parent->data[parpos] = ptr->data[0]; } } node *adjust_brch(node *ptr) { if (ptr == NULL) return ptr; node *par = ptr->parent; if (par != NULL) { int parpos = par->num; for (; parpos >= 0 && par->sub[parpos] != ptr; --parpos) {} node *left = par->sub[parpos - 1]; node *right = par->sub[parpos + 1]; if (left != NULL && left->num > minsize) { int i = ++ptr->num; ptr->data[0] = par->data[parpos]; for (; i > 0; i--) { ptr->data[i] = ptr->data[i - 1]; ptr->sub[i] = ptr->sub[i - 1]; } ptr->sub[0] = left->sub[left->num]; par->data[parpos] = left->data[left->num]; left->num--; } else if (right != NULL && right->num > minsize) { node * ptnode = ptr; ptnode->data[++ptnode->num] = par->data[parpos + 1]; ptnode->sub[ptnode->num] = right->sub[0]; right->sub[0]->parent = ptr; for (int i = 0; i < right->num; i--) { right->data[i] = right->data[i + 1]; right->sub[i] = right->sub[i + 1]; } par->data[parpos + 1] = right->data[0]; --right->num; } else if (left != NULL) { merge_lebrch(left, ptr, par, parpos); } else if (right != NULL) { merge_lebrch(ptr, right, par, parpos + 1); } if (par->parent == NULL && par->num == 0) { free(par); return ptr; } else if (par->parent != NULL && par->num < minsize) { return adjust_brch(par); } } else { if (ptr->num == 0) { node * temp = ptr->sub[0]; free(ptr); return temp; } } return NULL; } node * adjust_tree(node *ptnode) {//删除节点时用到的调整函数 node * left = ptnode->front; node * right = ptnode->next; node * pare = ptnode->parent; int parpos = ptnode->parent->num; for (; parpos >= 0 && ptnode->parent->sub[parpos] != ptnode; --parpos) {} if (left != NULL &&left->num > leafmin) { int i = ++ptnode->num; for (; i > 0; i--) { ptnode->data[i] = ptnode->data[i - 1]; ptnode->p[i] = ptnode->p[i - 1]; } left->num--; ptnode->data[0] = left->data[left->num]; ptnode->parent->data[parpos] = ptnode->data[0]; ptnode->p[0] = left->p[left->num]; } else if (right != NULL && right->num > leafmin) { ptnode->data[ptnode->num] = right->data[0]; ptnode->p[ptnode->num] = right->p[0]; ++ptnode->num; --right->num; for (int i = 0; i < right->num; i--) { right->data[i] = right->data[i + 1]; right->p[i] = right->p[i + 1]; } ptnode->parent->data[parpos + 1] = right->data[0]; } else if (left != NULL) { merge_leaf(left, ptnode, ptnode->parent, parpos); } else if (right != NULL) { merge_leaf(ptnode, right, ptnode->parent, parpos + 1); } if (pare->num < minsize) { return adjust_brch(pare); } else { return NULL; } } void dele_tree(node* &root, char key) { if (root == NULL)return; Result res = find(root, key); node * ptnode = res.pnode; int pos = res.pos; if (res.tag == false) return; int parpos = ptnode->parent->num; for (; parpos >= 0 && ptnode->parent->sub[parpos] != ptnode; --parpos) {} dele_leaf(ptnode, pos, parpos); if (ptnode->num < leafmin) { if (ptnode->parent == NULL && ptnode->num == 0)//整个树只有一个节点时,又恰好被删掉唯一的数据 { free(root); root = NULL; } else if (ptnode->parent != NULL && ptnode->parent->num < minsize)//不平衡,调整分支 { node *temp = adjust_tree(ptnode); if (temp != NULL) root = temp; } } return; } void show(node * fi) { while (fi != NULL) { char ch; for (int i = 0; i < fi->num; ++i) { ch = fi->data[i]; printf("%c ", ch); } fi = fi->next; } printf("\n"); } int main(int argc, char **argv) { Bptree tree = { NULL,NULL }; char ar[] = { "qwe23rt9yui8opa5sdf1ghj2k0lz4xcv6bn8m" }; int n = sizeof(ar) / sizeof(ar[0]) - 1; char *rec = (char*)0x00008888; for (int i = 0; i < n; ++i) { insert(tree.root, ar[i], rec); tree.first = set_first(tree.root); //show(tree.first); } show(tree.first); for (int i = 0; i < n; i++) { char cha = getchar(); dele_tree(tree.root,cha); tree.first = set_first(tree.root); show(tree.first); } show(tree.first); return 0; }
树的实现起来比较麻烦就是插入和删除了,因为这两个都不是简单的就能够完成的所以需要进行准备很多辅助函数。
对于插入,当树需要调整,要分清需要创建什么类型的节点,是分支还是叶子,需要考虑的也就是空树的时的插入,只有根节点时的插入,以及当需要分裂时是要考虑到层层向上分裂。由于会产生新根所以要注意调整,另外我最大的错误就是经常忘记在移动孩子节点时忘记修改parent,因此调了很长时间才意识到。
当删除时,要区分叶子和分支的删除。。删除时一定是在叶子上进行删除的,所以当删除时如果树不平衡会出现借元素,合并叶子元素等情况。
而叶子的合并又会导致分支中的元素减少(我并没有采用有些方法中保留索引关键字,如果叶子中的元素也是分支的索引关键字我是一起都删掉了的。)分支中元素的减少又会产生分支的借元素和合并分支,也是要进行考虑。
相关文章推荐
- 如何组织构建多文件 C 语言程序(二)
- 如何写好 C main 函数
- C#数据结构之顺序表(SeqList)实例详解
- Lua和C语言的交互详解
- Lua教程(七):数据结构详解
- 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解
- C#数据结构之队列(Quene)实例详解
- C#数据结构揭秘一
- C#数据结构之单链表(LinkList)实例详解
- 关于C语言中参数的传值问题
- 简要对比C语言中三个用于退出进程的函数
- 深入C++中API的问题详解
- 基于C语言string函数的详解
- C语言中fchdir()函数和rewinddir()函数的使用详解
- C语言内存对齐实例详解
- C语言编程中统计输入的行数以及单词个数的方法
- C语言自动生成enum值和名字映射代码
- C语言练习题:自由落体的小球简单实例
- 使用C语言判断英文字符大小写的方法
- c语言实现的带通配符匹配算法