在了解原理之前,得先科普几种数据结构
通过中序遍历
需满足条件
图 001
优点
每次经过一次节点时
最多可以减少一半的可能
缺点
图 001
中搜索值
为1的节点
不过极端情况会出现所有节点都位于同一侧
直观上看就是一条直线,那么这种查询的效率就比较低了
如CASE 1
会查询6次
优化(平衡树)
图 002
所谓平衡,说的是这棵树的各个分支的高度是均匀的
它的左子树和右子树的高度之差绝对值小于1
这样就不会出现一条支路特别长的情况
如图 002
于是,在这样的平衡树中进行查找时
总共比较节点的次数不超过树的高度
这就确保了查询的效率(时间复杂度为O(logn))
CASE 1
中的查询次数就会减小到4次了
具体怎么实现树平衡的
看本文的你不用深入了解
只用知道普通的树要变成平衡树,会在树的成员数量变化的时候,同时通过某些算法调整树就行了
如图 002
所示
因为树的节点的出度d(即,叶子节点个数)都是2
所以虽然图中只有9个节点,但是扫到关键字为1的节点要4次
对我们来说,应该先想办法把树的高度(深度,目前是4)变得矮
下面的B树
就是一个初步方案
B树 的别名是 B-树 ,英文名是Balance Tree
适用于外查找的树,它是一种平衡的多叉树
图 003
需满足条件
k-1
个元素和k个孩子,其中 m/2 <= k <= m
k-1
个元素,其中 m/2 <= k <= m
k-1
个元素正好是k
个孩子包含的元素的值域分划此外,每个节点上,会直接存储一些数据信息
对比二叉排序平衡树
搜索简述
示例,这是一个三阶的B树
图 004
相比磁盘I/O的速度,内存中的比较耗时几乎可以忽略
所以只要树的高度足够低,I/O次数足够少,就可以提升查找性能
现在我们树是变得矮了
示例,搜索关键字
为4的节点,如图 004
我们可以直接获取到这个节点所携带的信息了
B+树
是为磁盘或其他直接存取辅助设备而设计的一种平衡查找树
在B+
树中,所有记录节点都是按键值的大小顺序存放在同一层的叶节点中,各叶节点指针进行连接
图 005
需满足条件
如图 005
所示
在B+树
中查询一次数据需要I/O的次数=树的高度
其实 跳表
很像 B+树
的搜索过程, 后文我再讲解这种数据结构吧
跳表是基于有序链表的更适合内存结构
B+树是基于磁盘存储读取设计的数据结构
大多关系型数据库会选用 B+树
是考虑磁盘读取设计的
磁盘每次读取的最小单元是页(普遍是4k大小)
前文云天河写到的磁盘I/O
指的就是Mysql
每次读取页的操作
为了方便Mysql
在内存里识别节点信息
Mysql
设计的时候,是一个节点存一页大小
要想每页能读取的节点信息越多
那么树的阶数(出度d)要尽可能的大
d最大值 = floor(Pagesize/(Keysize + Datasize + Pointsize))
这样,树的高度才会越小,磁盘I/O次数就会小
树的高度
因为B树
每个节点直接包含了数据,而B+树
只包含了数据地址的指针
所以B+树
得出的最大出度会更大,磁盘I/O次数就会较少
B树
中一次检索最多需要h-1
次I/O(根节点常驻内存),渐进复杂度为O(h)=O(logdN)
一般实际应用中,出度d是非常大的数字,通常超过100,因此h非常小(通常不超过3)
范围查询
B树
查询单条数据是非常快的,但是范围查询的话,每次查到一条数据后都得重新中序遍历
然而B+树
的叶子节点都是有一个依据关键字大小顺序,指向下一个节点的链表连接着的,所以查范围会很方便
数据库 | 选用树 | 查询的时间复杂度 | 原因 |
---|---|---|---|
MongoDB | B树 |
最多h-1 次,渐进复杂度为O(h)=O(logd N) |
B树 恰好 key 和 data 域聚合在一起 |
Mysql | B+树 |
固定为 O(logd N) | a.内节点无 data 域,每个节点能索引的范围更大更精确 b.指针串在一起,这样就很容易的进行区间遍历甚至全部遍历 |
评论列表点此评论