Skip to content

02 The Polyphase Merge.md

我们已经知道了如何构建初始顺串,现在考虑各种合并模式,合并就是把顺串分布到各个磁带上,合并直至只剩一个顺串为止。

假定有三个磁带 ,考虑 5.4 里面描述的平衡合并,,形式如下: * B1. 交替的在 上分布顺串 * B2. 把 上的顺串合并到 ,如果 仅包含一个顺串时停止 * B3. 把 的顺串交替的拷贝回 ,跳到 B2

如果初始时有 个顺串,第一次合并将在 上产生 个顺串,第二次产生 ,以此类推。如果说 ,一次分配扫描,五次合并扫描,四次拷贝扫描。一般地,,扫描次数是

拷贝扫描完全是不必要的,因为并没有减少顺串。如果采用两阶段方式,可以减少一半的拷贝。 * A1. 交替的在 上分布顺串 * A2. 把 上的顺串合并到 ,如果 仅包含一个顺串时停止 * A3. 把 上一半的顺串拷贝到 上 * A4. 把 上的顺串合并到 ,如果 仅包含一个顺串时停止 * A5. 把 上一半的顺串拷贝到 ,跳回 A2

对数据扫描次数减少到了 ,因为 A3 和 A5 只拷贝了一半的数据,节省了大约 25% 的时间。

上有 个顺串, 上有 个顺串,其中 是连续的斐波那契数,那么可以完全消除不必要的拷贝。比如下面是 的情况:

Phase Contents of T1 Contents of T2 Contents of T3 Remarks
1 1,1,1,1,1,1,1,1,1,1,1,1,1 1,1,1,1,1,1,1,1 Initial distribution
2 1,1,1,1,1 - 2,2,2,2,2,2,2,2 Merge 8 runs to T3
3 - 3,3,3,3,3 2,2,2 Merge 5 runs to T2
4 5,5,5 3,3 - Merge 3 runs to T1
5 5 - 8,8 Merge 2 runs to T3
6 - 13 8 Merge 1 run to T2
7 21 - - Merge 1 run to T1

每个初始顺串长度为 1,2 表示长度为 2 的顺串,以此类推。上表中到处都是斐波那契数。

只有第一阶段和第七阶段对数据进行了完全扫描,第二阶段处理了 16/21,第三阶段仅仅处理了 15/21。如果假设初始顺串都差不多长,那么总共处理的数据量是 ,同样的数据两阶段需要 8 次扫描。一般地,满足这种斐波那契分布的模式,需要 次扫描,和 4个磁带的平衡合并一样快,但是只用了 3 个磁带。

同样的思想可以推广到 个磁带。对于 ,使用 路合并。后面会看到对于 4 个磁带的情况下,数据扫描次数是 。推广形式涉及到了广义的斐波那契数列。先考虑 的情况。

Phase T1 T2 T3 T4 T5 T6 Initial runs processed
1 - 31 + 30 + 28 + 24 + 16 = 129
2 - 16 × 5 = 80
3 - 8 × 9 = 72
4 - 4 × 17 = 68
5 - 2 × 33 = 66
6 - 1 × 65 = 65
7 - - - - - 1 × 129 = 129

这里 表示 31 个长度为 1 的顺串, 表示 8 个长度为 9 的顺串,等等。R. L. Gilstad 提出这种模式,称为多阶段合并(polyphase merge)。三个磁带的情况更早的时候由 B. K. Betz 提出的。

为了像上面的例子这样分配合并,我们需要完美的斐波那契分布。 时,自底向上看分布分别是 。现在我们面临以下四个问题: 1. 这些完全斐波那契数基于什么规则分布的? 2. 如果 不能对应完全斐波那契分布怎么办? 3. 我们应该如何设计初始分布使得它们在磁带上是期望的分布情况? 4. 个磁带, 个初始顺串,扫描多少次?

我们按序讨论这几个问题,先给出一个“简单的答案”,再进行更详细的分析。

完全斐波那契分布可以通过周期地转动磁带内容、向后运行而得到。下面是 的具体例子。

Level T1 T2 T3 T4 T5 Total Final output will be on
0 1 0 0 0 0 1 T1
1 1 1 1 1 1 5 T6
2 2 2 2 2 1 9 T5
3 4 4 4 3 2 17 T4
4 8 8 7 6 4 33 T3
5 16 15 14 12 8 65 T2
6 31 30 28 24 16 129 T1
7 61 59 55 47 31 253 T6
8 120 116 108 92 61 497 T5

初始化之后,T6 总是空的。 从 级,下面条件总是成立的: 同时,我们可以从 分析出它们之间的关系: 其中 时, 阶斐波那契数 定义如下: 也就是说开始的时候有 个 0 和一个 1,然后每个数是前面 个数之和。 时就是通常的斐波那契数列。对于更大 的序列,Narayana Pandita 开始研究,V. Schlegel 在前人的基础上给出了生成函数: 公式 最后一个等式告诉我们六个磁带多阶段合并,T1 顺串数是五阶斐波那契数

一般地,如果令 个磁带的多阶段合并分布对应于第 阶斐波那契数。对于 ,完全斐波那契分布情况下,第 个磁带在 级初始顺串是 所有磁带总的顺串数是 这样就解决了完全斐波那契分布的问题。对于任意 ,不能完全分布的话,要怎么做呢?

可以向平衡合并的例子一样,加入虚拟顺串,使得 是完全的。我们不会先讨论最优解,而是先讨论分布的方法和指定虚拟顺串的方法,该方法不见得是最优的,但是很简洁,而且比其他同样简洁的方法要好些。

算法 D (Polyphase merge sorting with "horizontal" distribution 该算法一次分布一个顺串,直到初始顺串都被分配了为止。然后时合并这些顺串。假定 个磁带,使用 路合并。磁带 用于保存输入,因为它不会被分配初始顺串。下面是要维护的一些状态: * ,我们追寻的完全斐波那契分布 * ,逻辑磁带 开头的虚拟顺串的个数 * ,逻辑磁带 对应的物理磁带号

下面是算法步骤: * D1. [Initialize.] 对于 ,初始化 。最后初始化 。 * D2. [Input to tape .] 写一个顺串到磁带号 的磁带,。如果所有顺串分配完毕,跳转到 D5。 * D3. [Advance .] 如果 然后跳转回 D2;否则如果 ,调转到 D4,否则设置 调回 D2。 * D4. [Up a level.] 设置 ,按 的顺序依次执行 。注意, 一直都是 0。这时,。设置 并跳转回 D2。 * D5. [Merge.] 如果 ,排序完成并且输出放在 TAPE[1] 上。否则把 合并到 直到 为空且。合并的时候做如下操作:如果对于所有的 ,都有 ,也就是所有的都是虚拟顺串,那么对于所有的 都执行 ,并且 ,否则的话从 的磁带 取出一个顺串进行合并,然后对于其他包含虚拟顺串的 执行 。这里,利用了一个假设信息,就是虚拟顺串在每个磁带的前面。 * D6. [Down a level.] 执行 ,并且将磁带 绕回。然后调转一下磁带集 ,然后调回 D5。

整个流程如下图所示:

步骤 D3 非常简洁的给出了分布的方法,就是假设有等量的虚拟顺串在每个磁带的开始。下图是六个磁带的具体例子,阴影部分是分配好的顺串,现在是从 4 级(33 个顺串)到 5 级(65 个顺串),开始分配顺串 34。假设只有 53 个初始顺串,那么大于等于 54 的顺串都是虚拟顺串了。这里虚拟顺串在磁带尾部,但是最好想象它们在头部,然后算法也是按照在头部描述的。

已经回答了三个问题,还剩一个就是扫描次数。六个磁带的详细情况列在了上面的表中,当 时,处理的初始顺串总数是 ,这里不包括初始分布时的扫描。习题 4 推导出生成函数 一般地,当 时,初始顺串的处理次数是 的系数加上初始分配的 。习题 5 到习题 7 会给出多阶段合并的渐进结果,下面的表是前几项:

Tapes Phases Passes Pass/phase Growth ratio
3 72% 1.6180340
4 62% 1.8392868
5 57% 1.9275620
6 54% 1.9659482
7 52% 1.9835828
8 51% 1.9919642
10 50% 1.9980295
20 50% 1.9999981

上表中的增长率是 ,表示每一级增长时,顺串个数增长的近似因子。扫描表示每个记录被处理的平均次数,即 乘以分布和合并阶段处理的初始顺串的总数。对于完全分布, 时,存在 ,在每种情况下扫描和阶段数最高是

下图展示了算法 D 处理不完全的情况下每个记录平均数扫描的次数,这是 的函数。对于 的时候,会有不高效的峰值,但是对于更多的磁带而言这种情况就不显著了。同时,8 或者 10 个磁带相比 6 个磁带,差距已经不大了。

习题

习题 1 可以参考算法 D 运行一下,也可以参考 的那个例子(一个表格)来分析前几级每个磁带怎么放置顺串。

1
2 3 4 5
6 7 8 9
10
13
11
14
12
15

16

17
18
20
24
29
19
21
25
30

22
26
31

23
27
32


28
33

习题 4 从公式 可以得到 TODO 补充 A Walk Through Combinatorics 关于生成函数的链接 两遍同乘 的,然后对 求和得到 由于 ,所以作用同时加上 1,可以得到 右边第一项 ,所以等于从 0 开始求和,可以写作 其余各项由于负数项都等于零,类似地,可以得到

从公式 可以得到关于 的公式 根据生成函数的加法和移位的原理