数据结构 多路查找树 ---------B树和B+树的简单介绍

参考连接:微信公众号 程序员小灰
https://mp.weixin.qq.com/s/rDCEFzoKHIjyHfI_bsz5Rw
https://mp.weixin.qq.com/s/jRZMMONW3QP43dsDKIV9VQ
本文为半原创,结合了 程序员小灰和本身的一些理解和总结,若有错误,请帮忙指出,感谢。
B树的简单介绍

前面咱们已经介绍了BST AVL树 BRT,那么,为何要B树和B+树呢?他们和以前介绍的三种树有何区别?
其实最明显的差别体如今多叉上,前面介绍的三种树都是二叉树。而B树和B+树是多路查找树,目的是优化磁盘访问的速度。以前介绍的三种树是索引树,节点直接的链接能够理解为指针,即每一个节点在磁盘中散列存储,像这样
这里写图片描述
想要访问红色节点,须要先访问绿色节点,根据绿色节点的左子树索引查找到红色节点位置,再访问红色节点。
咱们看下以前三种树的磁盘访问
假设访问以下的树的节点10
这里写图片描述
第一次访问
这里写图片描述
第二次访问
这里写图片描述
第三次访问
这里写图片描述
第四次访问
这里写图片描述
不难看出,一个节点的访问磁盘的次数取决于该节点在树上的高度。程序员

所以,为了减小访问磁盘的次数,就必须下降树的高度,使树变得“矮胖”,而B树和B+树都具备矮胖的特色
B树的定义

一个m阶的B树具备以下几个特征:(m阶中的m能够理解为B树的分叉数,好比5阶B树最大分叉是5)web

  • 1.根结点至少有两个子女。
  • 2.每一个中间节点包含k-1个元素和k个孩子,其中 m/2向上取整 <= k <= m
  • 3.每个叶子节点包含k-1个元素,其中 m/2向上取整 <= k <= m
  • 4.全部的叶子结点都位于同一层。
  • 5.每一个节点中的元素从小到大排列,节点当中k-1个元素正好是k个孩子包含的元素的值域分划。
    实例

这是一个B树
这里写图片描述
但实际上应该是这样的
这里写图片描述
每一个节点应该有n个数据域和n+1个指针域组成,叶子节点的指针域都为空。但为了做图简单,就不将指针域画出来了
实际m阶B树节点结构以下:
这里写图片描述
除了叶子节点,其他节点的指针域能够经过双亲节点或者孩子节点的索引看出来。数据库

以节点2,6为例,咱们看到
1<2
2<3<5<6
6<8微信

B树的磁盘访问

以上面的树为例
第1次磁盘IO:
这里写图片描述
在内存中定位(和9比较):
这里写图片描述
第2次磁盘IO:
这里写图片描述
在内存中定位(和2,6比较):
这里写图片描述
第3次磁盘IO:
这里写图片描述
在内存中定位(和3,5比较):
这里写图片描述
其实从图中能够看出,相同的数字,构建的平衡二叉树和B树的高度相差一。
从上面咱们看出
B树进行了三次IO访问和5次内存比较
平衡二叉树AVL树进行了4次IO访问和4次内存比较。
咱们知道,内存的访问速度是远远大于外存(IO)访问的速度的,所以,当m阶B树的m越大,单一节点的元素树越多,B树的高度就越低,IO访问的次数就越少。可是,也不是m越大越好,当m大到m个数据,外存一个磁盘页装不下就糟了。所以m是受磁盘页大小限制的
B树的插入和删除

B树也是一种自平衡树
插入分如下几种状况
1.能够直接插入的状况
2.插入后破环平衡(即破环B树的定义中的任意一个性质),须要进行分裂
删除
1.能够直接删除
2.直接删除后破环平衡,先向左右子树“借”节点
3.直接删除后破环平衡,左右子树“借”不到节点,合并子树
插入删除操做比较复杂,具体示例请参照参考连接svg

B树的应用

文件系统索引和部分非关系型数据库,如MongoDB。可是大多数关系型数据库使用B+树做为索引。那么B+树和B树相比有何优点呢?
提早透露一下,B+树适用于范围查找
B+树

定义

  • 1.有k个子树的中间节点包含有k个元素(B树中是k-1个元素),每一个元素不保存数据,只用来索引,全部数据都保存在叶子节点。
  • 2.全部的叶子结点中包含了所有元素的信息,及指向含这些元素记录的指针,且叶子结点自己依关键字的大小自小而大顺序连接。
  • 3.全部的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素。
    以下即是一个B+树
    这里写图片描述
    能够看到:
    1 每个双亲节点的元素均会出如今孩子节点中,而且是子节点的最大(或最小)元素,也就是说,B+树存在重复元素。
    2 其次能够看到叶子节点用指针相连,造成一个链表。
    3 另外,要注意,在当前树中,根节点的15表明整棵树的最大元素,因此,对B+树作插入是,要保证最大元素一定在根节点出现过(若是双亲节点的元素均会出如今孩子节点中,而且是子节点的最小元素,则须要反过来)
    4 因为每一个双亲节点均在孩子节点出现,也就是说,叶子节点包含了所有节点(固然,还包括没有在双亲节点出现的元素)
    这里写图片描述

B+树的查找

以前我看了B树查找的过程,那么在B+树中是如何查找元素3呢?
这里写图片描述
一共进行了3次IO
首先,因为B+树只有根节点存储了元素数据,因此必须查到叶子节点。其次因为非叶子节点只存储索引,因此能够存储的索引树更多,可以使得B+树的高度更低,IO次数更少。性能

相比于B树, B+树的优点

咱们看下B树的范围查找(3-11)
这里写图片描述
自顶向下,查找到范围的下限(3)–>中序遍历到元素6–>中序遍历到元素8–>中序遍历到元素9–>中序遍历到元素11,遍历结束优化

一样的元素构成的B+树的相同范围查找以下
这里写图片描述
自顶向下,查找到范围的下限(3)–>经过链表指针,遍历到元素6, 8–>经过链表指针,遍历到元素9, 11,遍历结束
因此说,相比于B树 B+树的优点有:编码

1.单一节点存储更多的元素,使得查询的IO次数更少。(单一节点存储更多的元素是由于B+的非叶子节点不存储数据,存的是索引)设计

2.全部查询都要查找到叶子节点,查询性能稳定。(一样是由于非叶子节点不存储数据,数据只有叶子节点有)3d

3.全部叶子节点造成有序链表,便于范围查询。

二叉搜索树 平衡二叉树 红黑树 B树 B+树的简单对比

简称 特色 平衡性 查找性能 插入 删除 优点 应用
二叉搜索树 BST 索引树,因为构建不稳定,查找效率不稳定 不稳定,跟具体构建树相关,最好O(logn),最差O(N) 直接插入 删除的是叶子节点或只有左或右子树比较简单,如同时存在左右子树,那么要找到前驱或后继代替原先节点,再删除 性能高于线性查找 暂未找到,欢迎补充
平衡二叉树 AVL 索引树,BST进化版,自平衡,查找效率稳定 最好最坏都是O(lgn) 最多须要2次旋转 最多须要lgN次旋转(参考,本人未证明) 高度平衡,进一步提高查询效率 暂未找到,欢迎补充
红黑树 RBT 索引树,BST进化版,自平衡,查找效率相对稳定 基本维持在O(lgn),最坏比AVL略差(2lg(n+1)) 最多须要2次旋转,3次变色 最多须要3次旋转(参考,本人未证明) 自平衡,进一步提高查询效率 Java中TreeSet和TreeMap,JDK 8之后,HashMap的设计
B树 ^ 多路查找树,提高IO效率,索引树进化而来 IO次数取决于高度,减小IO次数 1.能够直接插入的状况2.插入后破环平衡,须要进行分裂 1.能够直接删除2.直接删除后破环平衡,先向左右子树“借”节点3.直接删除后破环平衡,左右子树“借”不到节点,合并子树 下降IO次数 文件系统索引和部分非关系型数据库,如MongoDB
B+树 ^ 多路查找树,提高IO效率,B树进化版 进一步减小IO次数 相似B树 相似B树 进一步下降IO次数,范围查询方便,查询性能稳定 大多关系型数据库使用B+树做为索引
另外提一下哈夫曼树,上面的几个都是查找树,而哈夫曼树的设计不是为了查找,而是为了减小编码长度。哈夫曼树多应用于压缩技术(哈夫曼编码)