B树
搜索树
定义: 搜索树用于指导搜索记录
B树特点
- 提供多层次访问结构 (Multi-level Access Structure)
- 树总是平衡
- 删除造成的空间浪费永远不会过度。即:每个节点至少半满
- B树可以在非叶和叶节点存储值
- 每个不是根或叶的节点有⌈n/2⌉\lceil n/2 \rceil⌈n/2⌉到n个子节点;即,n表示最大子数,n称为树的度(order)
B+树索引文件
B+树是一种满足以下属性的有根的树:
- 从根到叶的所有路径都是相同的长度
- 非叶节点称为内部节点
- 每个不是根或叶的节点有⌈n/2⌉\lceil n/2 \rceil⌈n/2⌉到n个子节点
- 注意值的数量是少于子节点的数量的;即,⌈n/2⌉\lceil n/2 \rceil⌈n/2⌉–1和n-1之间,或等价的,⌈n/2⌉\lceil n/2 \rceil⌈n/2⌉和n-1值
如果n是偶数,对于一个不是根或叶的节点,值(value)或槽(slot)的数量可以略小于半满的,但如果n是奇数,则至少是半满的:
证明: 对于偶数n,值的最大数目为(n-1),且值的最小数目为⌈n/2⌉\lceil n/2 \rceil⌈n/2⌉-1 = n/2-1,最小满度为n2−1n−1=12n−2n−1<12\frac{\frac{n}{2}-1}{n-1} = \frac{1}{2}\frac{n-2}{n-1} < \frac{1}{2}n−12n−1=21n−1n−2<21当 n→∞,→12n \rightarrow \infty, \rightarrow \frac{1}{2}n→∞,→21 。
对于奇数n,值的最大数目为(n-1),最小数目为⌈n/2⌉\lceil n/2 \rceil⌈n/2⌉–1=(n-1)/2,如前所示,其最小满度为[(n−1)/2]/(n−1)=12[(n-1)/2]/(n-1)=\frac{1}{2}[(n−1)/2]/(n−1)=21
确保叶子节点的槽数至少半满,而不是使用下限⌈n/2⌉\lceil n/2 \rceil⌈n/2⌉–1,甚至可以不到一半满,我们修改⌈n/2⌉\lceil n/2 \rceil⌈n/2⌉
如果根不是一个叶子,它至少有两个孩子
B+树的例子(n = 4)
叶节点 在B+树(n = 4) 对于i=1,2,...,n−1i=1,2,..., n-1i=1,2,...,n−1,指针PiP_iPi指向一个文件记录与搜索键值KiK_iKi
如果Li,LjL_i,L_jLi,Lj叶节点和i<ji< ji<j,LiL_iLi的搜索键值(search-key values)小于或等于LjL_jLj的搜索键值
PnP_nPn指向下一个叶节点在搜索键顺序(协助顺序处理)
B+树的例子(n = 6)
B+树(n=6)用于教师文件,即6个指针和5个槽
叶节点必须在3到5个值之间(⌈n/2⌉\lceil n/2 \rceil⌈n/2⌉和n-1,其中n=6)。
除根以外的非叶节点必须有3到6个子节点(⌈n/2⌉\lceil n/2 \rceil⌈n/2⌉和n个子节点)的⇒在2到5个值之间。就值而言,这是小于半满(即,2/5 = 40%满)
然而,如果n = 7,那么非叶节点将有4到7个子值(⌈n/2⌉\lceil n/2 \rceil⌈n/2⌉和n个子值)⇒在3到6个值之间,这些值至少是半满的
根必须至少有2个子节点。
B+树的性能
B+树,每个节点包含m=⌈n/2⌉\lceil n/2 \rceil⌈n/2⌉和孩子(假设根行为像任何其他节点):
- 根节点的最小节点数=m0=m^0=m0(level 1)
- 第一层最小节点数 =m1= m^1=m1
- 第二层最小节点数 =m2=m^2=m2
- 第三层最小节点数 =m3= m^3=m3
- 第h层最小节点数 =mh−1= m^{h-1}=mh−1
每个叶节点将大致持有大约至少m个子节点,所以假设树的高度是h,叶节点持有的最小值数大约是mh−1m^{h-1}mh−1
如果文件中有K搜索键值,我们有mh=Km^h = Kmh=K, 如果h=⌈log⌈n/2⌉K⌉h =\lceil log_{\lceil n/2 \rceil} K \rceilh=⌈log⌈n/2⌉K⌉
通过假设每个节点的存储利用率最低,我们有树的最大节点数,因此树的最大高度。因此,如果文件中有K个搜索键值,树的高度不应该超过h=⌈log⌈n/2⌉K⌉h = \lceil log_{\lceil n/2 \rceil} K \rceilh=⌈log⌈n/2⌉K⌉(即我们假设所有节点都最小满;如果它们不是最小满,那么高度应该更小)
节点通常与磁盘块大小相同,通常是4kb假设每个索引项(index entry)40字节,B树的度n通常是100。
现在有100,0000个搜索键值和n=100,通过从根到叶的查找遍历来访问,最多有log501,000,000=3.53≈4log_{50}1,000,000 = 3.53 \approx 4log501,000,000=3.53≈4节点时被访问
与具有100万个搜索键值的平衡二叉树相比——大约访问20个节点log21000,000=19.93≈20log_21000,000=19.93≈20log21000,000=19.93≈20,上述差异很显著,因为每个节点访问可能需要一个磁盘I/O,花费约20毫秒
B树的平均存储利用率
设K为树中所有搜索键值的总数,n是一个节点的最大容量(即,一个节点可以保持在n/2和n个之间索引项)N为树中节点的随机数,ρ是树的随机存储利用率,f是最小满度因子,
标准B树的f=½,B*树的f=⅔
(随机)树的总存储容量为Nn
存储利用率是指项目总数除以所有节点的总存储容量,即ρ = K/(Nn)
现在,如果所有的节点都满了,就会产生一个最小的节点数,这就是K/n
同样地,如果所有节点都是半空的,则会产生最大的节点数,即K/(½n)=2K/n
对于上述节点范围内的每个构型都是等可能的随机插入,N的分布可以近似于长度为K/N,[K/N,2K/N]的区间上的连续均匀分布。
N∼U(K/n,2K/n)N\sim U(K/n, 2K/n)N∼U(K/n,2K/n)
因此,我们近似地,有
E(ρ)=E(K/[Nn])=(K/n)E(1/N)KnnK∫Kn2Kn1tdt=ln2Kn−lnKn=ln2=69.3%E(\rho)= E(K/[Nn])= (K/n)E(1/N)\\
\frac{K}{n}\frac{n}{K}\int^{2\frac{K}{n}}_{\frac{K}{n}}\frac{1}{t}dt = ln2\frac{K}{n} - ln\frac{K}{n} = ln2=69.3\% E(ρ)=E(K/[Nn])=(K/n)E(1/N)nKKn∫nK2nKt1dt=ln2nK−lnnK=ln2=69.3%
对于任意最小满度f的一般情况,N的分布可以近似于长度为Kf‘/(nf)的区间[K/n,K/(nf)]上的均匀分布,高度为nf/(Kf’)的均匀分布,其中f‘=1-f。
N∼U(K/n,2K/nf)N\sim U(K/n, 2K/nf)N∼U(K/n,2K/nf)
因此,我们近似地,有
E(ρ)=E(K/[Nn])=(K/n)E(1/N)KnnfKf′∫KnKnf1tdt=lnKnf−lnKn=ff′ln1fE(\rho)= E(K/[Nn])= (K/n)E(1/N)\\
\frac{K}{n}\frac{nf}{Kf'}\int^{\frac{K}{nf}}_{\frac{K}{n}}\frac{1}{t}dt = ln\frac{K}{nf} - ln\frac{K}{n} = \frac{f}{f'}ln\frac{1}{f}E(ρ)=E(K/[Nn])=(K/n)E(1/N)nKKf′nf∫nKnfKt1dt=lnnfK−lnnK=f′flnf1
对于B*-树,f =⅔,并将此值代入上述式子,我们得到E(ρ)=2×ln(3/2)≈81%
一般情况下的随机存储利用率
平均数通常是有限的。ρ的累积分布函数给出了随机情况的完整信息,可以显示为:
G(x)={1x>11f′(1−fx)f≤x≤10x<f
G(x)=\left\{
\begin{aligned}
1 \qquad \qquad x > 1\\
\frac{1}{f'}(1-\frac{f}{x}) \quad f \leq x \leq 1\\
0 \qquad \qquad x < f
\end{aligned}
\right.
G(x)=⎩⎨⎧1x>1f′1(1−xf)f≤x≤10x<f
即:P[ρ ≤ x] = G(x).对应的概率密度函数为
g(x)=G′(x)={ff′x2f≤x≤10x<f,x>1
g(x) = G'(x)=\left\{
\begin{aligned}
\frac{f}{f'x^2} \quad f \leq x \leq 1\\
0 \quad x < f ,x>1
\end{aligned}
\right.
g(x)=G′(x)=⎩⎨⎧f′x2ff≤x≤10x<f,x>1
存储利用率的方差
从上面给出的概率函数,方差很容易计算,可以显示为:
σf2=f−(ff′)2[ln(1f′)]2\sigma^2_f = f-(\frac{f}{f'})^2 [ln(\frac{1}{f'})]^2σf2=f−(f′f)2[ln(f′1)]2
B树的存储利用率标准差为0.14,B*树的存储利用率标准差为0.094。
更新B+树:插入
我们让
- Pr是指向记录的指针
- V是该记录的搜索键值
查找搜索键值的叶节点
- 如果叶节点中有空间,则在叶节点2中插入(V, Pr)对。
- 否则,拆分节点(连同新的(V, Pr)对)
拆分叶节点:
- 按排序顺序取n个(搜索键值、指针)对(包括正在插入的那对)。将第一个⌈n/2⌉\lceil n/2\rceil⌈n/2⌉个对放在原始节点中,其余的放在一个新节点中
- 设新节点为p,并设k为p中的最小键值。在被拆分的节点的父节点中插入(k, p)
- 如果父节点已满,则将其分割,并将其进一步传播
节点的拆分将向上进行,直到找到未满的节点。在最坏的情况下,根节点可以被分割,使树的高度增加1
更新B+树:删除
假定记录已从文件中删除。设V是该记录的搜索键值,而Pr是指向该记录的指针
- 从叶节点中删除(Pr, V)
- 如果由于删除而导致节点的条目太少,并且节点和兄弟节点中的条目适合于单个节点,则合并兄弟节点:将两个节点中的所有搜索键值插入单个节点(左边的节点),然后删除另一个节点
- 如果由于删除而导致节点的条目太少,但节点和兄弟节点中的条目不适合单个节点,则重新分配指针:在节点和兄弟节点之间重新分配指针,使两者都有超过最小的条目数量
- 更新父节点
- 节点删除可以向上级联,直到找到具有⌈n/2⌉\lceil n/2\rceil⌈n/2⌉或更多指针的节点
- 如果根节点在删除后只有一个指针,那么它将被删除,并且唯一的子节点将成为根节点
总结
B+ -Tree
- 实际记录在叶节点
B树
- 指向非叶节点中的实际记录
B*树
- 可以改变最小丰满因子f不同于f=½
- f=⅔,相应的树被称为B*-树