前言需求算法
咱们上一篇文章中介绍了平衡二叉树,以及为何会有平衡二叉树?sql
但其实二叉树的操做效率较高,其实也是存在一些问题的数据库
咱们通常二叉树加载存放到内存中构建成,假如节点比较多(亿:单位)性能
1.构建二叉树时,须要屡次进行I/O 操做
(海量数据存在数据库/文件
中),速度有影响
2.节点海量,会形成二叉树高度很大,下降操做速度学习
这时咱们就提出一种树想解决这个问题:多叉树
优化
1.在二叉树中
,每一个节点有数据项,最多有两个子节点
。若是容许每一个节点有更多数据项和更多的子节点
,就是多叉树(multiway Tree)
spa
2.多叉树经过从新组织节点,减小树的高度
,对二叉树进行优化设计
(示例图:2-3树、2-3-4树就是多叉树)3d
2-3树便是最简单的B树结构,具备如下特色:指针
一、全部叶子节点都在同一层(B树都知足这个条件)
二、有一个元素项且有两个子节点叫二节点、二节点要么有两个子节点、要么就没子节点
三、有二个元素项且有三个子节点叫三节点、三节点要么有三个子节点、要么就没子节点
四、由二节点与三节点构成的成为2-3树
咱们发现三节点EJ、有AC、H、L 子节点
其中它们的关系是 AC < H < L,而AC的关系又是 A < C的
将数列{16, 24, 12, 32, 14, 26, 34, 10, 8, 28, 38, 20}
构建成2-3树, 并保证数据插入的大小顺序。
第一步:插入:16 放入后成为二节点(二节点有一个元素项,两个子节点)
第二步:插入:24 放入后成为三节点(三节点有二个元素项,三个子节点)
第三步:插入:12 时按理说应该是插入16前面,可是插入16前行么?
不行,由于放入后就不是三节点了,变成了三个元素项了,咱们须要拆
第四步:插入:32 比16节点还要大,因此咱们从右子节点开始找位置
从右子节点找位置,尝试的从24 节点后边去放,判断是否知足三节点
第五步:插入:14 同理,比16节点小,因此从左子节点开始找位置
从左子节点找位置,尝试的从12 节点后边去放,判断是否知足三节点
第六步:插入:26 比16节点还要大,因此咱们从右子节点开始找位置
按理说咱们应该是放入2四、32 中间的,可是能放吗?
不行,放了就变成三个元素项了,而且也不能成为2四、32的子节点,由于放了三节点就只有一个子节点了,也不符合要求(三节点要么有三个子节点、要么就没子节点)
所以咱们只能往上拆,使插入26 节点也知足条件要求
第七步:插入:34 比26 大,因此咱们从右子节点开始找位置
从右子节点找位置,尝试的从32 节点后边去放,判断是否知足三节点
第八步:插入:10 比16节点小,因此从左子节点开始找位置
按理说咱们应该是放入12 前边的,可是能放吗?
不行,放了就变成三个元素项了,而且也不能成为十二、14的子节点,由于放了三节点就只有一个子节点了,也不符合要求(三节点要么有三个子节点、要么就没子节点)
那么按照以前的插入节点26的思路,咱们须要拆节点不是嘛?
可是此时并不知足B树的特色:全部叶子节点都在同一层
,因此咱们须要调整
第九步:插入:8 比16节点还要小,因此咱们从左子节点开始找位置
按理说咱们应该是放入12 前边的,可是12 有子节点,再进行寻找
从左子节点找位置,尝试的从10 节点前边去放,判断是否知足三节点
第十步:插入:28 比16节点大,因此咱们从右子节点开始找位置
按理说咱们应该是放入26 后边的,可是26有子节点,再进行判断寻找
按理说咱们应该是放入32 前边的,可是能放吗?
不行,放了就变成三个元素项了,而且也不能成为3二、34的子节点,由于放了三节点就只有一个子节点了,也不符合要求(三节点要么有三个子节点、要么就没子节点)
那么按照以前的插入节点的思路,咱们须要拆节点不是嘛?
第十一步:插入:38 比16节点大,因此咱们从右子节点开始找位置
按理说咱们应该是放入2六、32 后边的,可是放入后就变成三个元素项了,不过2六、32有子节点,再进行判断寻找。
从右子节点找位置,尝试的从34节点后边去放,判断是否知足三节点
第十二步:插入:20 比16节点大,因此咱们从右子节点开始找位置
按理说咱们应该是放入26,32 前边的,可是放入后就变成三个元素项了,不过2六、32有子节点,再进行判断寻找。
从左子节点找位置,尝试的从20节点前边去放,判断是否知足三节点
咱们能够看看B树的这些节点图来多多认识经过从新组织节点,减小树的高度
1.如图B树经过经过从新组织节点,减小树的高度
2.文件系统及数据库的设计者利用磁盘预读原理,将一个节点的大小设为等于一个页的大小(一般为4k)
,这样每一个节点只须要一次I/O 便可
3.将树的度M设置为1024,在600亿个元素中最多只须要4次I/O便可读取想要的元素
,普遍用于文件存储系统以及数据库系统中
(会不会有小伙伴提问:什么是树的度M?)
讲树的度M以前须要知道什么是节点的度?
通常来讲咱们都知道二叉树最多有两个子节点
假如A节点有B、C 两子节点,咱们称A节点的度为2,即度为子树有几个。
那么树的度呢?指全部节点的度里的最大的值,即为树的度M
咱们前面介绍的2-3树、甚至2-3-4树,它们也是属于B树,我能够先看看以前咱们学习Mysql时,常常听见某种类型的索引是基于B树或者B+树的原理是个什么状况呢?
咱们先说明B树的几个点:
第一点:B树有一个概念叫:阶,指的是节点的最多子节点个数,好比2-3树阶是3,2-3-4树的阶是4
第二点:B树的搜索:从根节点开始,对节点内的关键字(有序)序列进行二分查找,若是命中则结束,不然进入查询关键字所属范围的儿子节点,重复操做,直到所对应的儿子节点为指针为空或者已经是叶子节点
第三点:关键字集合分布在整颗树中,即叶子节点和非叶子节点都存放数据
第四点:搜索有可能在非叶子节点就结束
第五点:其搜索性能等价于在关键字全集内作一次二分查找
B+树是B树的变体,也是一种多路搜索树
咱们说明B+树与B树的一些特色
第一点:B+树的搜索与B树也基本相同,区别是B+树只有达到叶子节点才会命中(B树能够在非叶子节点命中)
,性能也等价于作一次二分查找
第二点:全部关键字都出如今叶子节点的链表中(数据只能在叶子节点),这叫稠密索引且链表中的关键字刚好是有序的
第三点:非叶子节点至关因而叶子节点的索引(稀疏索引),叶子节点是存储数据的数据层
第四点:不可能在非叶子节点命中
可能小伙伴会很奇怪,不是一上来就找到节点五?
一上来找到的实际上是索引,数据它在叶子节点上
咱们能够看看使用场景来体验一下B+树的结构
咱们不想一个一个的检索,那么有没有办法把这些数据分割成几部分?
咱们使用什么算法来体现出这种分割的思想呢?
假如咱们这时使用B+树的结构寻找28,咱们上来无需从一个节点一个节点开始,只须要找到范围的索引,一下就过滤了3/2的不符合范围的数据,某种意义来讲比二分还狠
B* 树是B+树的变体,在B+树的非根和非叶子节点上添加指向兄弟指针的操做
可是B* 树也有它的规定说明:
第一点:B 树定义了非叶子节点关键字个数至少为(2/3) M,即块最低使用率为2/3,而B+树的最低使用率为B+树的1/2
第二点:从第一点能够看出,B*树分配新节点的几率比B+树要低,空间使用率更高