B树的基本例程(1)插入
2015-09-01 09:12
281 查看
摘要:B树的基本定义:每个节点x都有以下域:
a)n[x],当前存储在节点x中的关键字数
b)n[x]个关键字本身,以非降序存放;
c)leaf[x],是一个布尔值,标志是否是叶子.
(2)每个节点内还包含n[x]+1个指向其子女的指针;
(3)每个节点都具有相同的深度h。
(4)每个节点能包含的关键字数有一个上界和下界,这些界可以用一个称作B数的最小度数的固定整数t来表示.t>=2;
(5)每个非根节点必须至少有t-1个关键字,每个非根节点内至少有t个子女。
(6)每个节点至多包含2t-1个关键字,所以一个内节点至多有2t个子女;
基本操作:
(1)搜索B树,搜索B树与搜索二叉查找树很相似,只是在每个节点所做的不是个二叉搜索,而是由该节点的子女数决定的.基本思路是遍历该节点的所有关键字,直到要搜索的元素x小于等于某个关键字或者大于所有关键字.
然后判断要搜索的元素就等于临界关键字,或者小于它.或者大于所有关键字.如果该节点是叶子,则没有子女,否则根据情况判断是否继续向下搜索.(这一部分的代码将直接运用到删除例程中)
(2)插入数据:因为B树的特点,因此必须将新的数据插入到一个叶子节点中.但是又不能将关键字插入到满叶子节点,故引入一个分裂操作,将一个满的节点从中间分裂成两个各含t-1个关键字的节点,而中间关键字则被提升到父节点.如果父节点也是满的,则它必须在关键字被插入前分裂.因此在查找过程中,遇到满节点就分裂,这样可以保证每分裂一个满节点时它的父节点不是满的。
a)n[x],当前存储在节点x中的关键字数
b)n[x]个关键字本身,以非降序存放;
c)leaf[x],是一个布尔值,标志是否是叶子.
(2)每个节点内还包含n[x]+1个指向其子女的指针;
(3)每个节点都具有相同的深度h。
(4)每个节点能包含的关键字数有一个上界和下界,这些界可以用一个称作B数的最小度数的固定整数t来表示.t>=2;
(5)每个非根节点必须至少有t-1个关键字,每个非根节点内至少有t个子女。
(6)每个节点至多包含2t-1个关键字,所以一个内节点至多有2t个子女;
基本操作:
(1)搜索B树,搜索B树与搜索二叉查找树很相似,只是在每个节点所做的不是个二叉搜索,而是由该节点的子女数决定的.基本思路是遍历该节点的所有关键字,直到要搜索的元素x小于等于某个关键字或者大于所有关键字.
然后判断要搜索的元素就等于临界关键字,或者小于它.或者大于所有关键字.如果该节点是叶子,则没有子女,否则根据情况判断是否继续向下搜索.(这一部分的代码将直接运用到删除例程中)
(2)插入数据:因为B树的特点,因此必须将新的数据插入到一个叶子节点中.但是又不能将关键字插入到满叶子节点,故引入一个分裂操作,将一个满的节点从中间分裂成两个各含t-1个关键字的节点,而中间关键字则被提升到父节点.如果父节点也是满的,则它必须在关键字被插入前分裂.因此在查找过程中,遇到满节点就分裂,这样可以保证每分裂一个满节点时它的父节点不是满的。
int maxIndex(Position p){ int i=0; for(;i<2*DU;i++){ if(p->data[i]==0) return i-1; //如果遇到了0说明前一个下标是最大的下标 } return 2*DU-2; //如果到了这里说明该节点是满节点,最大关键字下标是2*DU-2 } void shiftLeft(Position p,int start,int offset) { //start是开始移动的位置,offset 移动的位移 int tmp=start; int max=maxIndex(p); if(max==0) max=1; for(;tmp<=2*DU-2;tmp++) { //左移关键字 p->data[tmp]=p->data[tmp+offset]; p->data[tmp+offset]=0; //将无用的关键字置为0 } tmp=start; for(;tmp<=2*DU-1;tmp++) { p->child[tmp]=p->child[tmp+offset]; //左移子节点指针 p->child[tmp+offset]=NULL; //将无用的子节点指针置为NULL } } void shiftRight(Position p,int start) { //向右移动一位 int max=maxIndex(p); int index=max; //index 是key的下标 for(;index>=start;index--) p->data[index+1]=p->data[index]; //右移关键字数组 for(index = max + 1;index>=start;index--) p->child[index+1] = p->child[index]; } Position splitPage(Position p,int val) { //p节点为需要分裂的满节点,val是用来决定返回递归的新节点是B节点(原来的节点)还是新分裂的C节点 int mid=p->data[DU-1]; //取得p中间位置的节点,它被分裂到父节点中 Position right = pm(); //新建C节点 Position result; int index=DU; int i=0; for(;index<=2*DU-2;index++) { //开始复制B节点的关键字数组和子节点指针数组, right->data[i]=p->data[index]; p->data[index]=0; right->child[i]=p->child[index]; p->child[index]=NULL; if(right->child[i]!=NULL) right->child[i]->parent=right; //B节点的一部分子节点迁移到了C节点上,所以要重新设置子节点的父节点指针 i++; } right->child[i]=p->child[2*DU-1];//子节点指针数组比关键字数组个数多一个 if(right->child[DU-1]!=NULL) right->child[DU-1]->parent=right; //同时设置最后一个子节点指针的父节点 p->child[2*DU-1]=NULL; p->data[DU-1]=0; right->isLeaf=p->isLeaf; //设置C节点是否是叶子节点, if(p->parent==NULL) { //如果p节点就是根节点了,那么需要新生成Root节点 Position root = pm(); p->parent=root; root->isLeaf=0; } Position parent=p->parent; int first=0; for(;first<= 2*DU-2;first++){//取得父节点中mid可插入的位置 if(parent->data[first]>mid||parent->data[first]==0) break; } index=2*DU-3; for(;index>=first;index--) { //关键字和子节点指针数组右移1位 parent->data[index+1]=parent->data[index]; parent->child[index+2]=parent->child[index+1]; } parent->data[first]=mid; //插入新的关键字mid,和新的子节点指针right parent->child[first+1]=right; parent->child[first] = p;//避免生成新节点第一个子节点信息缺少 right->parent=parent; result = val > mid ? right:p; //确定返回的节点 return result; } void InsertData(Position p,int val) { //p表示目的节点,val表示要插入的值 if(pageSize(p)==2*DU-1){ //如果递归的过程中碰到满节点,就先分裂p节点 p=splitPage(p,val); //分裂的过程后,重新设置p节点 } int index=0; for(;index<sizeof(p->data)/sizeof(int);index++) { //寻找子节点的位置,因为分裂节点保证了p节点不是满节点,所以不用考虑满节点的情况(满节点的话index需要加1) if(p->data[index]==0||p->data[index]>val){ break; } } if(p->isLeaf==0) { //如果不是叶子节点,递归插入到子节点 InsertData(p->child[index],val); return ; } if(pageSize(p)>0) //如果节点中有关键字则右移1个位置 shiftRight(p,index); p->data[index]=val; //把新的关键字插入到相应的位置 return; }
相关文章推荐
- hdu-5385
- MySQL互为主从复制以及主主互备
- jenkins+svn搭建
- Spring常见面试题目
- Linux命令之stty - 显示和修改终端行设置
- Java面向对象
- 2015年08月25日作业-Linux用户和组管理
- iOS中uiimage和uicolor相互转化
- 设计模式: 自己手动写一个状态模式
- js获取某元素的class里面的css属性值代码(转)
- angular定制组件-toastr(消息提醒)
- 当我们开始谈论实体经济
- 亿级商品详情页架构演进技术解密 | 高可用架构系列 二
- C# 启动控制台直接打开一个网站
- 快速排序实现和改善
- 关于char越界的简单c
- request.getRemoteUser() 方法
- XMPP协议原理及相关信息。
- Jquery常用的方法汇总
- 有继续反弹动能 但分化将扩大