我试着阅读一些有关n路合并的文章,但却不理解这个概念。我很困惑你为什么要在双向合并中使用n路合并?就像你为什么要将数组分为3个部分,然后对它们进行排序然后进行2部分的2路合并,然后将第3部分的2路合并与此合并的2部分:)
由于
答案 0 :(得分:12)
当您进行外部排序时,通常最终会有多个要合并的流。例如,假设您需要对数TB的数据进行排序,并且只有(例如)64 GB的RAM。
您通常通过读取64 GB,对其进行排序,然后将其写出来来实现。重复完整的TB级数据,为每个可以在内存中保存的“块”生成一个中间文件。有很多方法可以改进这一点,但是您通常希望的最好的方法是生成大约128千兆字节的已排序中间文件。
这会让你有许多中间文件要合并在一起 - 这个数字肯定会大于2。
如果您要定期执行此操作,您可能需要使用一些非常高端的硬件。如果您将每个中间文件放在一个单独的磁盘驱动器上(并且至少还有一个用于输出),您几乎可以肯定通过一次合并所有数据来提高速度,而不是一次只合并两个。该过程通常是I / O限制的,因此一次从(例如)8个磁盘读取的速度通常是一次仅从2个磁盘读取的速度的4倍(尽管这取决于具有那么多带宽的输出磁盘) ,这可能不是真的)。通过避免创建更多的中间文件(需要进一步合并),您的整体速度可能会提高一个更大的因素。
答案 1 :(得分:8)
在“正常”合并排序中,将数组除以2,直到达到log2n
的深度,然后开始合并。两个大小为m
的数组的每次合并也会进行2m
次操作。
这将使您进入以下公式(在时序分析中):
n/2 * 2 + n/4 * 4 + ... 1 * n = n * log2n
现在,如果你进行三向合并,你将把数组除以3.与前一种方法的区别是双重的:
log3n
。这意味着,在最基本的实现中,您将获得这样的公式:
n/3 * 2*3 + n/9 * 2*9 + ... 1 * 2*n = 2 * n * log3n
请注意,2乘以,因为找到三个元素的最小值包含2个操作。
渐近地,这两个都是Θ(nlogn)
。但是,也许(我没有尝试过)在实践中,三向合并排序会因其log3n
而提供更好的性能。然而,由于n = 1000000的log2n
仅为20,而相同数字的log3n
为12.5,我怀疑除非n
非常大,否则此优化将非常有效。
通过巧妙的实现,k-way合并确实可以对合并排序产生很好的影响。我们的想法是,一旦找到最小的k
元素,您就已经知道其余k-1
元素之间的关系并非最小。因此,一旦从其各自的列表中消耗该最小元素,您只需要比较该列表的新值并找到与剩余的k-1
元素相关的排序。使用堆,这将是非常简单的。
请务必同时查看Jerry's answer。我同意他的看法,多路合并的真正威力来自于处理多个磁盘和并行处理。