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. goroutine调度源码阅读笔记

    以下为本人阅读goroutine调度源码随手记的笔记,现在还是一个个知识点的形式,暂时还没整理,先发到这里,一点点更新:   1). runq [256]guintptr P 的runable队列最大 ...

  2. 求100以内所有奇数的和,存于字变量X中。

    问题 求100以内所有奇数的和,存于字变量X中. 代码 data segment x dw ? data ends stack segment stack db 100 dup(?) stack en ...

  3. asp.net core 3.1多种身份验证方案,cookie和jwt混合认证授权

    开发了一个公司内部系统,使用asp.net core 3.1.在开发用户认证授权使用的是简单的cookie认证方式,然后开发好了要写几个接口给其它系统调用数据.并且只是几个简单的接口不准备再重新部署一 ...

  4. cryptopp使用Qt mingw编译,以及海思平台交叉编译

    编译工程生成,使用qmake生成qt工程文件(海思平台时,要用海思平台的qmake),将 TEMPLATE = app 修改为: TEMPLATE = lib 添加如下: win32:LIBS += ...

  5. Python面向对象编程扑克牌发牌程序,另含大量Python代码!

    1. 题目 编写程序, 4名牌手打牌,计算机随机将52张牌(不含大小鬼)发给4名牌手,在屏幕上显示每位牌手的牌. 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不 ...

  6. JS 图片跟随鼠标移动案例

    css代码 img { position: absolute; /* top: 2px; */ width: 50px; height: 50px; } HTML代码 <img src=&quo ...

  7. Docker 搭建 Keycloak

    Docker 搭建 Keycloak 命令 需要创建好数据库,启动容器指定数据库信息 # KEYCLOAK_USER 用户名 # KEYCLOAK_PASSWORD 密码 # DB_ADDR 数据库地 ...

  8. 微信公众号添加zip

    微信公众号添加zip的教程 我们都知道创建一个微信公众号,在公众号中发布一些文章是非常简单的,但公众号添加附件下载的功能却被限制,如今可以使用小程序“微附件”进行在公众号中添加附件. 以下是公众号添加 ...

  9. 5.深入k8s:StatefulSet控制器

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com 在上一篇中,讲解了容器持久化存储,从中我们知道什么是PV和PVC,这一篇我们讲通过Sta ...

  10. akka-typed(9) - 业务分片、整合,谈谈lagom, 需要吗?

    在讨论lagom之前,先从遇到的需求开始介绍:现代企业的it系统变得越来越多元化.复杂化了.线上.线下各种系统必须用某种方式集成在一起.从各种it系统的基本共性分析:最明显的特征应该是后台数据库的角色 ...