B树是平衡的m路搜索树。

根结点至少两个子女,根结点以外的非失败结点至少⌈m/2⌉个子女,所有失败结点都在h+1层。

第h层至少2⌈m/2⌉h-1个结点,因此失败结点数n+1≥2⌈m/2⌉h-1个。

每个结点包含一组指针recptr[m],指向实际记录的存放地址。recptr[i]与key[i]形成了一个索引项

注:key[0]~key[n]和ptr[0]~ptr[n](n<m)

1.B树的插入

每个非失败结点都有⌈m/2⌉-1~m-1个关键码,插入后超过范围的话需要分裂结点。

前⌈m/2⌉-1个关键码形成结点p,后m-⌈m/2⌉个结点形成结点q,第⌈m/2⌉个关键码和指向q的指针插入到p的父结点。

最差情况下,自顶向下搜索叶结点需要h次读盘,自底向上分裂路径上每一个结点。分裂非根结点时插入两个结点,分裂根结点时插入三个结点。需要读写磁盘次数=3h+1(不考虑读入的结点再向上插入时需要重新从磁盘读入)

当m较大时,访问磁盘的平均次数接近h+1。

2.B树的删除

如果被删关键码不在叶结点,在删去后就找其后一个指针指向的子树里最小的关键码x替代,再删去叶结点的关键码x。

在叶结点中删去关键码:

(1)被删关键码所在结点是根结点、结点关键码个数n≥2,直接删除关键码并将结点写回磁盘。

(2)被删关键码所在结点不是根结点、结点关键码个数n≥⌈m/2⌉,,直接删除关键码并将结点写回磁盘。

(3)被删关键码在叶结点、结点关键码个数n=⌈m/2⌉-1、相邻右兄弟/左兄弟结点关键码个数n≥⌈m/2⌉

①将父结点刚刚好大于/小于待删关键码的关键码下移到待删关键码的位置。

②将右兄弟/左兄弟结点中的最小/最大关键码上移到父结点的该位置。

③将右兄弟/左兄弟结点的最左/右子树指针平移到被删关键码所在结点的最后/最前子树指针位置。

④右/左兄弟结点被移走了一个关键码和一个指针,需要要剩下的填补调整,结点的关键码个数n也要减1。

(4)被删关键码在叶结点、结点关键码个数n=⌈m/2⌉-1、相邻右兄弟/左兄弟结点关键码个数n=⌈m/2⌉-1,则需要合并结点。

①将父结点p刚刚好大于待删关键码的关键码下移到待删关键码的位置。

②将若要合并p中子树指针pi和所pi+1指向的结点,并保留pi指向的结点,则将Ki+1关键码下移。

③把要指向pi结点全部关键码和指针都移到pi+1指向结点,并将其删除。

④p结点被移走了一个关键码和一个指针,需要要剩下的填补调整,结点的关键码个数n也要减1。

⑤如果p结点是根结点且关键码个数减少到了0,则将其删去,合并后结点作为新根;如果p结点不是根结点且关键码个数减少到了⌈m/2⌉-1,它要和自己的兄弟结点合并并重复该过程;

template <class T>
class Btree:public Mtree<T>{ //B树类继承自m树
public:
Btree();
bool Insert(const T& x);
bool Remove(T& x);
void LeftAdjust(MtreeNode<T> *p,MtreeNode<T> *q,int d,int j);
void RightAdjust(MtreeNode<T> *p,MtreeNode<T> *q,int d,int j);
void compress(MtreeNode<T> *p,int j);
void merge(MtreeNode<T> *p,MtreeNode<T>* q,MtreeNode<T> *pl,int j);
}; template <class T>
bool Btree<T>::Insert(const T& x){
//将关键码x插入到一个驻留在磁盘的m阶B树中
Triple<T> loc=Search(x);
if(!loc.tag) return false; //已存在
MtreeNode<T> *p=loc.r,*q; //p是关键码要插入的结点地址
MtreeNode<T> *ap=NULL,*t; //ap是插入码x的右邻指针
T k=x;int j=loc.i; //(k,ap)形成插入二元组
while(){
if(p->n<m-){ //结点关键码个数未超出
insertkey(p,j,k,ap);
PutNode(p);
return true;
}
int s=(m+)/; //准备分裂结点
insertkey(p,j,k,ap); //插入后p->n达到m
q=new MtreeNode<T>;
move(p,q,s,m); //将p的key[s+1..m]和ptr[s..m]移动到q的key[1..s-1]和ptr[0..s-1],p->n改为s-1,q->n改为m-s
k=p->key[s]; ap=q; //(k,ap)形成向上插入二元组
if(p->parent!=NULL){
t=p->parent;GetNode(t);
j=;
t->key[(t->n)+]=MAXKEY;
while(t->key[j+]<k) j++; //搜索,找到大于K的关键码停止
q->parent=p->parent;
PutNode(p);PutNode(q);
p=t; //p上升到父结点,继续调整
}
else{ //原p为根,需要产生新根
root=new MtreeNode<T>;
root->n=;root->parent=NULL;
root->key[]=k;
root->ptr[]=p;
root->ptr[]=ap;
q->parent=p->parent=root;
PutNode(p);PutNode(q);PutNode(root);
return true;
}
}
} template <class T>
bool Btree<T>::Remove(const T& x){
Triple<T> loc=Search(x);
if(loc.tag) return false; //未找到
MtreeNode<T> *p=loc.r,*q,*s;
int j=loc.i; //p->key[j]==x
if(p->ptr[j]!=NULL){ //非叶结点
s=p->ptr[j];GetNode(s);q=p;
while(s!=NULL){
q=s;
s=s->ptr[];
}
p->key[j]=q->key[];
compress(q,); //把结点q中1以后的指针和关键码前移,删除key[1]
p=q;
}
else compress(p,j); //叶结点,直接删除
int d=(m+)/;
while(){
if(p->n<d-){ //小于最小限制
j=;q=p->parent;
GetNode(q);
while(j<=q->n && q->ptr[j]!=p)
j++;
if(!j) LeftAdjust(p,q,d,j);
else RightAdjust(p,q,d,j);
p=q;
if(p==root) break;
}
else break;
}
if(root->n==){
p=root->ptr[];
delete root;
root=p;
root->parent=NULL;
}
return true;
} template <class T>
void LeftAdjust(MtreeNode<T> *p,MtreeNode<T> *q,int d,int j){
MtreeNode<T> *pl=q->ptr[j+];
if(pl->n>d-){ //右兄弟空间还够,仅做调整
p->n++;
p->key[p->n]=q->key[j+];
q->key[j+]=pl->key[];
p->ptr[p->n]=pl->ptr[];
pl->ptr[]=pl->ptr[];
compress(pl,);
}
else merge(p,q,pl,j+); //p与pl合并,保留p结点
} template <class T>
void RightAdjust(MtreeNode<T> *p,MtreeNode<T> *q,int d,int j){ } void compress(MtreeNode<T> *p,int j){
for(int i=j; i<p-n; i++){ //左移
p->key[i]=p->key[i+];
p->ptr[i]=p->ptr[i+];
}
p->n--; //结点中元素个数减1
}
void merge(MtreeNode<T> *p,MtreeNode<T>* q,MtreeNode<T> *pl,int j){
p->key[(p->n)+]=q->key[j];
p->ptr[(p->n)+]=pl->ptr[];
for(int i=; i<=pl->n; i++){
p->key[(p->n)+i+]=pl->key[i];
p->ptr[(p->n)+i+]=pl->ptr[i];
}
compress(q,j);
p->n=p->n+pl->n+;
delete pl;
}

算法-搜索(6)B树的更多相关文章

  1. 算法进阶面试题05——树形dp解决步骤、返回最大搜索二叉子树的大小、二叉树最远两节点的距离、晚会最大活跃度、手撕缓存结构LRU

    接着第四课的内容,加入部分第五课的内容,主要介绍树形dp和LRU 第一题: 给定一棵二叉树的头节点head,请返回最大搜索二叉子树的大小 二叉树的套路 统一处理逻辑:假设以每个节点为头的这棵树,他的最 ...

  2. 从K近邻算法谈到KD树、SIFT+BBF算法

    转自 http://blog.csdn.net/v_july_v/article/details/8203674 ,感谢july的辛勤劳动 前言 前两日,在微博上说:“到今天为止,我至少亏欠了3篇文章 ...

  3. Java数据结构和算法 - 什么是2-3-4树

    Q1: 什么是2-3-4树? A1: 在介绍2-3-4树之前,我们先说明二叉树和多叉树的概念. 二叉树:每个节点有一个数据项,最多有两个子节点. 多叉树:(multiway tree)允许每个节点有更 ...

  4. 【程序员的吃鸡大法】利用OCR文字识别+百度算法搜索,玩转冲顶大会、百万英雄、芝士超人等答题赢奖金游戏

    [先上一张效果图]: 一.原理: 其实原理很简单: 1.手机投屏到电脑: 2.截取投屏画面的题目部分,进行识别,得到题目和三个答案: 3.将答案按照一定的算法,进行搜索,得出推荐答案: 4.添加了一些 ...

  5. 算法导轮之B树的学习

    最近学习了算法导轮里B树相关的知识,在此写一篇博客作为总结. 1.引言 B树是为磁盘或其他直接存取的辅助存储设备而设计的一种平衡搜索树.B树类似于红黑树,但它与红黑树最大不同之处在于B树的节点可以拥有 ...

  6. Java数据结构和算法(一)树

    Java数据结构和算法(一)树 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 前面讲到的链表.栈和队列都是一对一的线性结构, ...

  7. 利用OCR文字识别+百度算法搜索,玩转冲顶大会、百万英雄、芝士超人等答题赢奖金游戏

    [先上一张效果图]: 一.原理: 其实原理很简单: 1.手机投屏到电脑: 2.截取投屏画面的题目部分,进行识别,得到题目和三个答案: 3.将答案按照一定的算法,进行搜索,得出推荐答案: 4.添加了一些 ...

  8. bs4--官文--搜索文档树

    搜索文档树 Beautiful Soup定义了很多搜索方法,这里着重介绍2个: find() 和 find_all() .其它方法的参数和用法类似,请读者举一反三. 再以“爱丽丝”文档作为例子: ht ...

  9. 0算法基础学算法 搜索篇第二讲 BFS广度优先搜索的思想

    dfs前置知识: 递归链接:0基础算法基础学算法 第六弹 递归 - 球君 - 博客园 (cnblogs.com) dfs深度优先搜索:0基础学算法 搜索篇第一讲 深度优先搜索 - 球君 - 博客园 ( ...

  10. loj#6072 苹果树(折半搜索,矩阵树定理,容斥)

    loj#6072 苹果树(折半搜索,矩阵树定理,容斥) loj 题解时间 $ n \le 40 $ . 无比精确的数字. 很明显只要一个方案不超过 $ limits $ ,之后的计算就跟选哪个没关系了 ...

随机推荐

  1. PHP 类型比较

    PHP 类型比较 虽然 PHP 是弱类型语言,但也需要明白变量类型及它们的意义,因为我们经常需要对 PHP 变量进行比较,包含松散和严格比较. 松散比较:使用两个等号 == 比较,只比较值,不比较类型 ...

  2. 牛客挑战赛39 D 牛牛的数学题 NTT FMT FWT

    LINK:牛牛的数学题 题目看起来很不可做的样子. 但是 不难分析一下i,j之间的关系. 对于x=i|j且i&j==0, i,j一定是x的子集 我们可以暴力枚举子集来处理x这个数组. 考虑 x ...

  3. luogu P2510 [HAOI2008]下落的圆盘

    LINK:下落的圆盘 计算几何.n个圆在平面上编号大的圆将编号小的圆覆盖求最后所有没有被覆盖的圆的边缘的总长度. 在做这道题之前有几个前置知识. 极坐标系:在平面内 由极点 极轴 和 极径组成的坐标系 ...

  4. ubuntu18.04右键怎么添加新建空白文本文件

    安装好ubuntu18.04发现右键菜单中没有新建空白文件了,这样工作的时候需要创建文本文件就不是很方便了,这里我们就可以通过以下的方式把新建空白文件添加到右键 解决办法: 1.打开文件夹,在用户主目 ...

  5. layui 事件监听触发

    1:监听select 改变 <!-- 不用form 用div也可以 --> <form class="layui-form"> <div class= ...

  6. ElasticSearch 7.8.1 从入门到精通

    学前导读 ElasticSearch对电脑配置要求较高,内存至少4G以上,空闲2G内存,线程数4018+ 学习的时候,推荐将ElasticSearch安装到Linux或者mac上,极度不推荐装Wind ...

  7. 【LifecycleException】: org.apache.catalina.LifecycleException: A child container failed during start 解决

    看了好多种解决方案: 第一种:从tomcat remove project -> clean project -> reboot project; 第二种:说用到的 jasper jsp解 ...

  8. tableau用户留存分析

    1.数据源 这是个母婴产品的购买流水数据 2.数据处理 字段拆分.创建购买点会员生命周期 3.分析不同省份的留存率情况 根据第12个月的留存率对省市进行分组 实际业务中也可以通过类似的方法对用户年龄组 ...

  9. C#算法设计排序篇之08-计数排序(附带动画演示程序)

    计数排序(Counting Sort) 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/689 访问. 计数排序是一个非基 ...

  10. 树莓派 4B VNC Viewer 显示 cannot currently show the desktop 的解决方法 (图文)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/ZChen1996/article/de ...