B树和B+树(平衡多路查找树)

链接:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

在这里插入图片描述

可以点击 Indexing 下的 B Trees 和 B+ Trees 去学习。

为什么需要B树

对 B 树的需求随着访问物理存储介质(如硬盘)的时间减少而增加。辅助存储设备速度较慢,容量较大。需要这种类型的数据结构来最大限度地减少磁盘访问。

其他数据结构如二叉搜索树、avl 树、红黑树等只能在一个节点中存储一个键。如果必须存储大量键,则此类树的高度将变得非常大,并且访问时间也会增加。

但是,B 树可以在单个节点中存储许多键,并且可以有多个子节点。这大大降低了高度,允许更快的磁盘访问。

B- 树和 B 树都指的都是 B 树,此外还有 B+ 树。

B 树的特点

可以把 B 树理解为一个有序的多叉树。

满足下列要求的 m 阶树:

(1)每个节点最多拥有 m 个孩子结点(即至多有 m-1 个关键字)

(2)每个结点的结构为

在这里插入图片描述

第一个位置的 n 用来表示结点有多少个关键字。
Pn 表示子树的指针,顺着指针可以找到子树的位置。
k 表示关键字。

例如:m = 4 的 4 阶 B 树

在这里插入图片描述

(3)除根节点外,其他结点至少有 m / 2 (向上取整)个孩子结点。

(4)若根节点不是叶子结点,则根节点至少有两个孩子结点。

(5)所有叶子结点都在同一层上,即B树是所有结点的平衡因子均等于0的多路查找树。

(6)除根节点外,其他节点都包含 n 个 key ,其中 [m/2]-1<=n<=m-1。

B树的查找

已知一棵三阶 B 树如下图所示,给出在 B 树中查找 37 的过程。

在这里插入图片描述
查找37,根节点是48,48>37,看48的左子树,25<37,看25的右子树,37=37。

那具体是怎么查找的呢??

首先来了解一下操作系统的磁盘预读。

磁盘预读:

  • 内存跟磁盘发生数据交互的时候,一般情况下有一个最小的逻辑单元,称之为页,datapage。
  • 页一般由操作系统决定是多大,一般是4k或者16k,我们在数据交互时,可以取页的整数倍来进行读取。

CPU要先把数据加载到内存中然后磁盘从内存中读取数据。

在这里插入图片描述

比如说这个 word 文档右击查看它的属性,虽然大小是46.9KB,但是占用空间是48KB,这是4K的整数倍,也就是磁盘加载数据到内存中都是datapage的整数倍。

在这里插入图片描述

我们可以结合操作系统知识理解 B 树的查找过程。

键值:表中的主键
指针:存储子节点的信息
数据:表记录中除主键外的数据

在这里插入图片描述

B树的每一个结点都是放在磁盘块里的,且一般规定磁盘块大小是16K

假如要在图中找一个关键字为28的数据:

首先把磁盘上的这个块加载到内存里,16<28,34>28,找到磁盘块1的p2,这是进行的第一次IO。

在这里插入图片描述

然后顺着磁盘块1的p2找到磁盘块3,再把磁盘块3加载到内存里面,然后28<25,28>31,找到磁盘块3的p2了。这是第二次IO。

在这里插入图片描述

然后顺着磁盘块3的p2找到磁盘块8,再把磁盘块8加载到内存里,28=28,返回关键字28对应的data。这是第三次IO。

在这里插入图片描述

B+树的引入

现在这个B树总共有三层,每个结点 datapage 是 16k ,假设指针和关键字不占用 datapage (占用很小),每个 data 占用 1k ,所以三层 B 树可以存储的 data 个数是16*16*16=2^12=4096条,还是在不考虑指针和关键字的 datapage 情况下的。所以如果要是存 10000 条数据的时候怎么办呢?或许你想到的是再给 B 树加一层,确实可以这样存储 10000 条数据,但是这样的话层数增多了,查找数据就要再多一次 IO 操作,再多一次 IO 操作那查找的速度不就又慢了吗?

在这里插入图片描述
那为什么 B 树要存储更多数据只能增加层数呢?因为存储空间都用来放 data 了,如果只存指针和关键字的话所占用的磁盘空间是非常小的,所以我们可以把 data 都放在叶子结点上,非叶子结点只存指针和关键字,可以提升查找速度,这就是 B+ 树

在这里插入图片描述

B+ 树结构长这样:

在这里插入图片描述

datapage 还是 16k ,假设每对指针和关键字(例如 上图磁盘块1的p1 ,28 )只占 10 个字节,那么一个结点可以存16000/10=1600个数据,三层结构可以存储 1600*1600*1600 千万级数据,存储的数据是非常多的。

B树的删除

已知一棵 5 阶(度)B 树如下图所示,给出在B树中删除 80、200、180、50、140 的过程。

在这里插入图片描述

要将删除非叶子节点的关键字转换为删除叶子节点关键字。在 B 树性质里,m阶树,除根节点外,其他节点都包含 n 个 key ,其中 [m/2]-1<=n<=m-1

如果节点删除一个关键字后,节点关键字依然大于 [m/2]-1个,那么不需要去做任何的变动直接删除就可以;如果删除关键字后小于 [m/2]-1个key,那么就需要让下一个节点的关键字补上来

在 B 树中删除 80、200、180、50、140 的过程如下:

  • 删除 80 :删除 80 后,节点关键字依然大于等于 2 个,那么不需要去做任何的变动直接删除就可以。
  • 删除 200 :删除 200 后节点关键字是 1 个,所以如果要删除 200 ,那么就要先找到 200 的下一个关键字,230,让 230 代替 200 ,然后再删掉 230 。
    在这里插入图片描述
  • 删除180:如果删除的是 180(此时已经删除 200 ),此节点只有一个关键字不满足节点关键字 >= 2 。
    在这里插入图片描述
    那么需要让父节点 230 代替 180 ,再让子节点 240 补上原来 230 的位置,才能仍满足每个节点关键字 >= 2 ,结果如下:
    在这里插入图片描述
  • 删除 50 :删除 50 后该节点关键字个数为 1 ,需要再加 1 个关键字才能满足B树性质,但是它的兄弟节点都是 2 个关键字,没法再给它一个关键字了,所以这个时候就需要找父节点要一个关键字(兄弟没有钱时找爸爸要)。
    在这里插入图片描述
    那么此时就先把父节点拉下来一个关键字。
    在这里插入图片描述
    然后再把兄弟节点合并了。
    在这里插入图片描述
    此时父节点不够两个关键字,那么需要找父节点的兄弟节点要一个关键字,如果父节点的兄弟节点没有关键字,那么就找父节点的父节点的父节点要一个关键字(爸爸找兄弟借,兄弟也没有那就找爷爷借),所以只能降低树的高度,变成了下面这样。
    在这里插入图片描述
    然后发现没有根节点,所以把兄弟节点进行合并,变成一个正常的 B 树。
    在这里插入图片描述
  • 删除 140 :删除 140 后,变成了这样。
    在这里插入图片描述
    然后从父节点拿一个关键字,变成了这样。
    在这里插入图片描述
    为了维持 B 树的特点再和兄弟节点进行合并,最终结果就是这样。
    在这里插入图片描述
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

铃音.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值