爱抄书

可扩散列

2022-05-12  本文已影响0人  Sun东辉

如果需要处理的数据量太大以至于装不进去主存,我们就要考虑检索数据所需的磁盘存取次数了。

我们假设在任意时刻都有 N 个记录要存储,N 的值随时间而变化。此外,最多可把 M 个记录放入一个磁盘区块。

如果使用开放定址散列法或分离链接散列法,那么主要的问题在于,在一次 Find 操作期间,冲突可能引起多个区块被考察,甚至对于理想分布的散列表也在所难免。不仅如此,当表变得过满的时候,必须执行代价巨大的再散列这一步,它需要 O(N) 次磁盘访问。

一种聪明的选择叫作可扩散列(extendible hashing),它允许用两次磁盘访问执行一次 Find。插入操作也需要很好的磁盘访问。

我们都知道,B 树具有深度 O(\log{\frac{M}2}N)。随着 M 的增加, B 树的深度降低。理论上我们可以选择使得 B 树的深度为 1 的 M。此时,在第一次以后的任何 Find 都将花费一次磁盘访问,因为据推测根节点可能存在主存中。这种方法的问题在于分支系数(branching fator)太高,以至于为了确定数据在哪片树叶上要进行大量的处理工作。如果运行这一步的时间可以缩减,那么我们就将有一个实际的方案。这正是可扩散列使用的策略:

可扩散列使用的策略

上图是一个可扩散列的扩展实例。具体的过程为,插入 100100 时,它将进入第三片树叶,但是第三片树叶已经满了,没有空间存放它。因此我们将这片树叶分裂成两片树叶,它们由前三位确定(左图的树叶由前两位确定)。这时,需要将目录的大小增加到 3。注意,此时,所有未被分裂的树叶现在各由两个相邻目录项所指。因此,虽然重写整个目录,但是其他树叶都没有被实际访问。

如果现在插入关键字 000000,那么第一片树叶就要被分裂,生成两片树叶,故此时,目录中所做的唯一变化是 000 和 001 指针的更新。如下图:

插入关键字 000000

这个非常简单的方法提供了对大型数据库 Insert 操作和 Find 操作的快速存取时间。这里,还有一些重要的细节尚未考虑:

这些可能性指出,这些位完全随机是相当重要的,这可以通过把关键字散列到合理长的整数(由此得名)来完成。

树叶的期望个数为 (N/M)\log_2 e。因此,平均树叶满的程度为 \ln 2 = 0.69。这和 B 树是一样的,其实这完全不奇怪,因为对于两种数据结构,当添加第 (M+1)项时,一些新的节点就建立起来了。

更惊奇的结果是,目录的期望大小(换句话说即 2^D)为 O(\frac{N^{1+\frac{1}{M}}}M)。如果 M 很小,那么目录可能过大。这种情况下,我们可以让树叶包含指向记录的指针而不是实际的记录,这样可以增加 M 的值。为了维持更小的目录,我们为每个 Find 操作添加第二个磁盘访问。如果目录太大装不进主存,那么第二个磁盘怎么说也还是需要的。

上一篇下一篇

猜你喜欢

热点阅读