理解B树的设计与定义

一:如何减少IO访问次数

设计出B树的目的是解决数据过大时,内存存不下的时候需要把数据存在拥有更大空间的磁盘,那么什么样子的数据结构才是合适的?往下看:
考虑左下图的一棵二叉树,需要在E结点写入一个数据,首先就需要找到E节点,查找路径为 A->B->E,假设A节点存储在内存(根节点),其余节点存储在磁盘内,首先需要从磁盘将B节点读取出来,然后根据B节点的内容从磁盘中将E节点读出来,很容易发现E结点当前高度为3,只需要访问2次IO,那么如果我需要对X节点(高度为H)进行读写呢?就需要 (H-1) 次IO访问,每次IO访问操作系统进行的磁盘寻址取数是一个耗时的过程(根据机器性能会有几毫秒),所以要尽量减少磁盘的访问次数,就需要把树的高度降低,那么同样的结点数,只需要让每层可以容纳更多的元素就可以降低层高了,二叉树每个结点只有一个元素,那我是不是可以让每个结点有多个元素?二叉树每层只有2(n-1)个结点,是不是可以更多?所以B树就被设计成类右下图的样子,实际结点分叉更多,结点包含的元素也更多
在这里插入图片描述

有人会问:为什么非根节点不存到内存?
数据过大指的就是节点数据过大,假设每个结点存1K数据,单个节点存内存没问题,一旦节点很多时,在存内存就不够了
又有人问:那我只存索引不行吗?
如上诉问题,假设索引也有1K的时候怎么办?

二:如何正确访问到每一个元素(毕竟需要增删改查)

依然与二叉树做比较,二叉树是小的元素为左节点,大的元素做右节点,通过这种关系可以由上至下访问到每个元素,如左下图,
那么对于多叉多元素如何访问呢?
首先对于节点内的元素来说,里面应该得顺序或者逆序排列,这样通过索引就能访问到节点内的元素,对于节点A来说元素10就是他的第二个数据
然后是子节点,这里借用数学区间的概念,如右下图【6,10】把数字空间分为了3部分:小于6、大于6小于10、大于10,所以他有3个子节点
ps:标红的都是节点
在这里插入图片描述

三:B树的定义
在给出正式定义之前,先阐述自己的观点:

1、节点元素尽可能多,分叉尽可能多,但不是无限多:为了减少IO访问次数,也就是树高度尽可能低,理论上,只要你分叉够多,结点包含的元素够多,树高2层就够你存储所有的数据了,实际上却不不一样,哪怕你每个结点包含再多元素,最终还是对磁盘读写,而磁盘访问的单位是1个扇区,也就是说每次磁盘访问是有大小限制的,考虑机器性能,一般的节点大小都会设置为一个磁盘页

对于典型的磁盘来说,一页的长度 在211~214个字节

2、数据结构的设计一定是为了解决某种问题才思考出来的方案,假如磁盘这类的持久化存储设备访问速度很快,就没有B树这一概念了。
3、数据结构得能让人较容易的去使用,所以你会看到很多定义里面各种条件限制,个人理解是为了方便数据结构元素的插入删除而加的限制

那有人又会问了,到底是先有性质还是先有数据结构?
这就是先有鸡还是现有蛋的问题了,我觉得是先遇到的问题,才有的多叉多元素的结构,然后为了更好的定义才约定的限制,加了限制的多叉多元素结构就成了B树,然后这些限制就成了B树的性质

正式的定义

1、某个视频里面看到的定义

一颗M阶B树T,满足以下条件

  1. 每个结点至多拥有M课子树
  2. 根结点至少拥有两颗子树
  3. 除了根结点以外,其余每个分支结点至少拥有M/2课子树
  4. 所有的叶结点都在同一层上
  5. 有k课子树的分支结点则存在k-1个关键字,关键字按照递增顺序进行排序
  6. 关键字数量满足ceil(M/2)-1 <= n <= M-1

2、百度百科的定义

一棵m阶B树(balanced tree of order m)是一棵平衡的m路搜索树。它或者是空树,或者是满足下列性质的树:
1、根结点至少有两个子女;
2、每个非根节点所包含的关键字个数 j 满足:┌m/2┐ - 1 <= j <= m - 1;
3、除根结点以外的所有结点(不包括叶子结点)的度数正好是关键字总数加1,故内部子树个数 k 满足:┌m/2┐ <= k <= m ;
4、所有的叶子结点都位于同一层。
在B-树中,每个结点中关键字从小到大排列,并且当该结点的孩子是非叶子结点时,该k-1个关键字正好是k个孩子包含的关键字的值域的分划。
因为叶子结点不包含关键字,所以可以把叶子结点看成在树里实际上并不存在外部结点,指向这些外部结点的指针为空,叶子结点的数目正好等于树中所包含的关键字总个数加1。
B-树中的一个包含n个关键字,n+1个指针的结点的一般形式为: (n,P0,K1,P1,K2,P2,…,Kn,Pn)
其中,Ki为关键字,K1<K2<…<Kn, Pi 是指向包括Ki到Ki+1之间的关键字的子树的指针。

3、算法导论给出的定义:
在这里插入图片描述

在理解这些定义前可以想象一个场景,B树的节点数量是如何一个一个增加的,也就是B树的数据插入过程,正常来说是根据关键字的大小插入合适的位置,如下图:
在这里插入图片描述
但是每个节点大小都会有限制(前面有提到),也就是节点的关键字个数是有最大值的,那么我假设这个最大值为max,当一个节点的关键字个数为max时,在增加一个数,怎么处理?参考如下过程,假设max=4,当需要增加关键字为80的数据时,先将数据添加进节点,然后从中间分列,中间元素上移到父节点,
在这里插入图片描述
删除的话比较复杂,但演算的时候可以采取了增加的逆过程,当节点小于max/2时去删除,则想办法合并,所以按照这个编码思路,那么你的B树自然而然会包含这个关键性质(不管你是定义“阶”还是“度”还是子节点个数限制,本质都是一样的)

节点关键字个数 大于max/2 ,小于max

这是从编码实现推出性质,我觉得这应该也是正确的过程

发现问题(磁盘访问次数太多)
在现有基础上解决问题(多叉搜索树)
想办法编码实现极端情况(增删过程的分裂合并)
得出B树性质

当然正常来说我们都是直接根据性质来编码,这样的话理解起来就会有些问题,我也是这样过来的,像《算法导论》给出的定义每个节点最多包含2t-1个关键字,目的是为了保证最大个数的值为奇数,但在实现增加时,他会先分裂在添加。

PS:
1、代码实现就不再次多说了
2、B+树,是在多叉树的基础上要求所有叶子节点在一个层高,同时数据都保存在叶子节点上

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

dai1396734

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

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

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

打赏作者

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

抵扣说明:

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

余额充值