Loading

B树和B+树

B树

B树定义

B 树又叫平衡多路查找树。一棵m阶的B 树 (m叉树)的特性如下

  • B树中所有节点的孩子节点数中的最大值称为B树的阶,记为M(重点
  • 树中的每个节点至多有M棵子树 ---即:如果定了M,则这个B树中任何节点的子节点数量都不能超过M
  • 若根节点不是终端节点,则至少有两棵子树
  • 除根节点和叶节点外,所有点至少有m/2棵子树(上溢)
  • 所有的叶子结点都位于同一层。(比如上面的图片中我没有了11 13 15,那么我12就没有存在的意义了,就需要调整整个树的布局)

比如m阶B树,

所有的结点的分支都不得超过m,每个结点内的元素按顺序排列;

根节点至少1个元素,2个分支;最多m-1个元素,m个分支;

中间节点,则至少m/2(向上取整)个分支,元素个数为分支个数-1;

所有的叶子结点都位于同一层。

B树插入

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

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

B树删除

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

B+树

B+树的特征

  • 有m个子树的中间节点包含有m个元素(B树中是k-1个元素),每个元素不保存数据,只用来索引;
  • 所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大的顺序链接。 (而B 树的叶子节点并没有包括全部需要查找的信息);
  • 所有的非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大(或最小)关键字。 (而B 树的非终节点也包含需要查找的有效信息);

为什么说B+树比B树更适合数据库索引?

1)B+树的磁盘读写代价更低

  B+树的内部结点并没有指向关键字具体信息的指针。因此其内部结点相对B 树更小。如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了;

2)B+树查询效率更加稳定

  由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当;

3)B+树便于范围查询(最重要的原因,范围查找是数据库的常态)

  B树在提高了IO性能的同时并没有解决元素遍历的效率低下的问题,正是为了解决这个问题,B+树应用而生。B+树只需要去遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,而B树不支持这样的操作或者说效率太低;不懂可以看看这篇解读-》范围查找

补充:B树的范围查找用的是中序遍历,而B+树用的是在链表上遍历;

img

posted @ 2021-02-03 13:45  沿途有余弦  阅读(235)  评论(0)    收藏  举报