找了好长时间关于B+树的时间复杂度的博客,没找到几篇相关的,有相关的博客基本都是错误的,当然不排除我没找到的情况。
B+树的建立我就简单的说一下,避免大家搞混B树和B+树,这也是面试官喜欢考察的地方(好多面试官对这里也是比较糊涂的,因为面试官不一定是做数据库或者索引相关研究的)。
B树和B+树最大的区别就是,B树是将各种信息保存在所有节点中的,B+树是将各种信息保存在叶子中的。这样一来,对于每一个要查找的值来说,B+树都需要从根节点到叶子节点找一遍,那么时间复杂度与树高成正比;B树只需要找到相应节点就停止查找,所用时间从 O ( 1 ) − O ( h ) O(1)-O(h) O(1)−O(h)都有可能。由此看来,B+树性能看似比B树更差(既然这样,为啥还用B+树?),但是所用时间更稳定(为什么稳定性重要?)。
先来看看B+树的结构:
上图是一个典型的B+树非叶子节点构成。14,52,78是索引值,不是实际的值。
上图就是一个B+树,n=3。什么是n,一会说。
每个非叶子节点的pointer指向下一个节点。你看,由于数据结构的原因,我们不会为每个节点分配不同的数据结构存储信息,所以对于上图的B+树,每个节点保存3个索引值和4个pointer值。对于23, 31, 43
这个节点,最左pointer指向索引值小于23
却大于左侧节点(7)的索引值的节点。而索引值为31
的下方有两个pointer,左边是指向小于31
的,右边是指向大于等于31
而小于43
的指针。到了叶子节点,2
下面就成了只有一个指针,指向响应的磁盘块,同样的,3, 5
也均指向响应的磁盘块,还剩一个指针指向下一个节点。这个指针在做范围查询的时候比较有用:我们从根节点到叶子节点找到范围下界,再进行遍历到上界即可,所需要的时间复杂度是 O ( n + h ) O(n+h) O(n+h),如果是没有这个指针,我们需要遍历每一个树杈,时间复杂度是 O ( n ∗ h ) O(n*h) O(n∗h),这里的 h h h是树高。
什么是上面提到的n?
B+树将结构分为三部分:
- 根节点
- 中间节点
- 叶子节点
这篇文章并不是给初学B+树的同学看的,重点是后面的时间复杂度,所以怎么维持B+树, 每个节点的性质就不提了。
我们把每个节点成为“块”, 英文是block。而每个节点内部最多含有多少索引值,这个数目就是n。这个n又称为B+树的阶,英文是order of B+tree。 因此,当我们知道n的值时,我们便知道了该节点的子树有几棵。
比如n=3
,则子树就有4棵的,假设一个根节点是22, 28, 35
,那么该树的分叉为i<=22, 22<i<=28, i<28<=35,i>35
。当然这只是针对于满B+树,还有的情况是阶为3,它的部分子树为空。
一个盘pointer指向一个block。一个节点共有n+1
个pointer,n
个索引值有: ( n + 1 ) ∗ ∣ b l o c k a d