什么是B-树。什么是B树。B-树的插入。B-树的删除。

目录

一.前言

二.B树的概述

三.B树的插入操作 

四.B树的删除操作

五.B树的应用


一.前言

首先我们得先明白B-树就是B树,中间的橫线并不是减号。其次,数据库系统普遍采用B-/+Tree作为索引结构,理解不透彻B树,则无法理解数据库的索引机制。

那为什么数据库索引结构不使用二叉树来实现呢?

虽然平衡二叉树的查找效率是非常高的,并可以通过降低树的深度来提高查找的效率。但是当数据量非常大,树的存储的元素数量是有限的,这样会导致二叉查找树结构由于树的深度过大而造成磁盘I/O读写过于频繁,进而导致查询效率低下。另外数据量过大会导致内存空间不够容纳平衡二叉树所有结点的情况。而B树是解决这个问题的很好的结构。

索引查询的数据主要受限于硬盘的I/O速度,查询I/O次数越少,速度越快,所以B树的结构才应需求而生;B树的每个节点的元素可以视为一次I/O读取,树的高度表示最多的I/O次数,在相同数量的总元素个数下,每个节点的元素个数越多,高度越低,查询所需的I/O次数越少。

所以查询效率和树的高度密切相关,最坏情况下,磁盘IO次数等于索引树的高度。

二.B树的概述

B树是一种多路平衡查找树,它的每一个节点最多包含k个孩子,k被称为B树的阶。k的大小取决于磁盘页的大小。

什么是B树的阶 ?

上图所有节点中,节点【13,16,19】拥有的子节点数目最多,四个子节点【11,12】【14,15】【17,18】【20,21】,所以可以定义上面的图片为4阶B树。

什么是叶子节点?

上图中节点【1,2】、节点【11,12】等最后一层都为叶子节点,叶子节点对元素的数量有相同的限制,但是没有子节点,也没有指向子节点的指针。

什么是节点的元素个数?

上图中节点【7,8,9】的元素个数为3,即7,8,9。 

一棵含有n个总关键字数的m阶的B树的最大高度是多少?

而作为一棵m阶的B树,他必须要满足以下几点:

  • 每个节点最多只有m个子节点。
  • 非叶子节点的子节点个数:m/2 <= x <= m
  • 根节点的子节点个数:2<= x <= m
  • 每个非根节点所包含的元素个数 j 满足:m/2 <= j <= m - 1。
  • 根节点的元素个数满足:1<= x <= m-1
  • 所有的叶子结点都位于同一层。
  • 每个节点中的元素都是从小到大排好序的。

三.B树的插入操作 

针对m阶高度h的B树,插入一个元素时,首先在B树中是否存在,如果不存在,即在叶子结点处结束,然后在叶子结点中插入该新的元素。

  • 若该叶子节点元素个数小于m-1,直接插入;
  • 若该叶子节点元素个数等于m-1,引起节点分裂;以该节点中间元素为分界,取中间元素(偶数个数,中间两个随机选取)插入到父节点中;
  • 重复上面动作,直到所有节点符合B树的规则;最坏的情况一直分裂到根节点,生成新的根节点,高度增加1;

上面三段话为插入动作的核心,接下来以5阶B树为例,详细讲解插入的动作;

5阶B树关键点:

  • 2<=根节点子节点个数<=5
  • 1<=根节点元素个数<=4
  • 2<=非根节点元素个数<=4

图(1)插入元素8后变为图(2),此时根节点元素个数为5,不符合 1<=根节点元素个数<=4,进行分裂(真实情况是先分裂,然后插入元素,这里是为了直观而先插入元素,下面的操作都一样,不再赘述),取节点中间元素7,加入到父节点,左右分裂为2个节点,如图(3)

接着插入元素5,11,17时,不需要任何分裂操作,如图(4) 

插入元素13

节点元素超出最大数量,进行分裂,提取中间元素13,插入到父节点当中,如图(6)

    

 接着插入元素6,12,20,23时,不需要任何分裂操作,如图(7)

插入26时,最右的叶子结点空间满了,需要进行分裂操作,中间元素20上移到父节点中,注意通过上移中间元素,树最终还是保持平衡,分裂结果的结点存在2个关键字元素。

插入4时,导致最左边的叶子结点被分裂,4恰好也是中间元素,上移到父节点中,然后元素16,18,24,25陆续插入不需要任何分裂操作。

 

最后,当插入19时,含有14,16,17,18的结点需要分裂,把中间元素17上移到父节点中,但是情况来了,父节点中空间已经满了,所以也要进行分裂,将父节点中的中间元素13上移到新形成的根结点中,这样具体插入操作的完成。

四.B树的删除操作

首先查找B树中需删除的元素,如果该元素在B树中存在,则将该元素在其结点中进行删除;删除该元素后,首先判断该元素是否有左右孩子结点,如果有,则上移孩子结点中的某相近元素(“左孩子最右边的节点”或“右孩子最左边的节点”)到父节点中,然后是移动之后的情况;如果没有,直接删除。

  • 某结点中元素数目小于ceil(m/2)-1向上取整,则需要看其某相邻兄弟结点是否丰满;ceil(value) 返回不小于value的最小整数。
  • 如果丰满(结点中元素个数大于(m/2)-1),则向父节点借一个元素来满足条件;
  • 如果其相邻兄弟都不丰满,即其结点数目等于(m/2)-1,则该结点与其相邻的某一兄弟结点进行“合并”成一个结点;

接下来还以5阶B树为例,详细讲解删除的动作;

  • 关键要领,元素个数小于 2(m/2 -1)就合并,大于4(m-1)就分裂

如图依次删除依次删除8,20,18,5

首先删除元素8,当然首先查找8,8在一个叶子结点中,删除后该叶子结点元素个数为2,符合B树规则,操作很简单,咱们只需要移动11至原来8的位置,移动12至11的位置(也就是结点中删除元素后面的元素向前移动

 下一步,删除20,因为20没有在叶子结点中,而是在中间结点中找到,咱们发现他的继承者23(字母升序的下个元素),将23上移到20的位置,然后将孩子结点中的23进行删除,这里恰好删除后,该孩子结点中元素个数大于2,无需进行合并操作。

下一步删除18,18在叶子结点中,但是该结点中元素数目为2,删除导致只有1个元素,已经小于最小元素数目2,而由前面我们已经知道:如果其某个相邻兄弟结点中比较丰满(元素个数大于ceil(5/2)-1=2),则可以向父结点借一个元素,然后将最丰满的相邻兄弟结点中上移最后或最前一个元素到父节点中,在这个实例中,右相邻兄弟结点中比较丰满(3个元素大于2),所以先向父节点借一个元素23下移到该叶子结点中,代替原来19的位置,19前移;然后24在相邻右兄弟结点中上移到父结点中,最后在相邻右兄弟结点中删除24,后面元素前移。

最后一步删除5, 删除后会导致很多问题,因为5所在的结点数目刚好达标,刚好满足最小元素个数(ceil(5/2)-1=2),而相邻的兄弟结点也是同样的情况,删除一个元素都不能满足条件,所以需要该节点与某相邻兄弟结点进行合并操作;首先移动父结点中的元素(该元素在两个需要合并的两个结点元素之间)下移到其子结点中,然后将这两个结点进行合并成一个结点。所以在该实例中,咱们首先将父节点中的元素4下移到已经删除5而只有6的结点中,然后将含有4和6的结点和含有1,3的相邻兄弟结点进行合并成一个结点。

也许你认为这样删除操作已经结束了,其实不然,在看看上图,对于这种特殊情况,你立即会发现父节点只包含一个元素7,没达标(因为非根节点包括叶子结点的元素K必须满足于2=<K<=4,而此处的K=1),这是不能够接受的。如果这个问题结点的相邻兄弟比较丰满,则可以向父结点借一个元素。而此时兄弟节点元素刚好为2,刚刚满足,只能进行合并,而根结点中的唯一元素13下移到子结点,这样,树的高度减少一层。

五.B树的应用

B-树主要应用于文件系统以及部分数据库索引,比如著名的非关系型数据库 MongoDB。

猜你喜欢

转载自blog.csdn.net/ThinPikachu/article/details/113894282
今日推荐