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. Centos 7下编译安装Mysql

    (1)官网下载地址:https://dev.mysql.com/downloads/mysql/ 此处下载的是 mysql-boost-5.7..tar.gz 百度云下载地址:https://pan. ...

  2. 让你的GitHub下载飞速提升到2M/s以上

    2020年7月27日整理发布多种GitHub加速方式! 转载自:https://code.pingbook.top/blog/2020/How-To-Speed-Github.html 1. GitH ...

  3. 详解 MySQL 面试核心知识点

    一.常见存储引擎 1.1 InnoDB InnoDB 是 MySQL 5.5 之后默认的存储引擎,它具有高可靠.高性能的特点,主要具备以下优势: DML 操作完全遵循 ACID 模型,支持事务,支持崩 ...

  4. [草稿]Skill 中如何读取一个文件并打印出来

    https://www.cnblogs.com/yeungchie/ path = "~/hello" file = infile(path) while(gets(x file) ...

  5. 【问题记录】ajax dataType属性

    最近整理代码,发现一些ajax dataType 属性值设置的问题.下面直接上代码说明下 前台ajax请求 $.ajax({ type: "get", dataType: &quo ...

  6. 线性DP 学习笔记

    前言:线性DP是DP中最基础的.趁着这次复习认真学一下,打好基础. ------------------ 一·几点建议 1.明确状态的定义 比如:$f[i]$的意义是已经处理了前$i个元素,还是处理第 ...

  7. Android Studio--APK打包

    首先在app的build.gradle里面加一下代码 lintOptions { checkReleaseBuilds false abortOnError false } 在上方Build里面找到G ...

  8. Python玩转各种多媒体,视频、音频到图片

    我们经常会遇到一些对于多媒体文件修改的操作,像是对视频文件的操作:视频剪辑.字幕编辑.分离音频.视频音频混流等.又比如对音频文件的操作:音频剪辑,音频格式转换.再比如我们最常用的图片文件,格式转换.各 ...

  9. CenterNet文献调研记录

    心仪院校导师任务之一,文献调研记录. 本文部分思路参考: 1. Anchor-Free 2. https://zhuanlan.zhihu.com/p/66048276 3. https://blog ...

  10. 操作属性、操作样式 - DOM编程

    1. 操作属性 1.1 HTML 属性与 DOM 属性的对应 <div> <label for="username">User Name: </lab ...