N路合并排序2G字符串文件

时间:2012-05-21 00:15:11

标签: java algorithm sorting

这是破解编码访谈的另一个问题,我在阅读后仍有一些疑问。

9.4 If you have a 2 GB file with one string per line, which sorting algorithm 
    would you use to sort the file and why?

当面试官给出2GB的大小限制时,它应该告诉你一些东西 - 在这种情况下,它表明他们不希望你把所有数据都带入内存。 那么我们该怎么办?我们只将部分数据带入内存.. 算法:

我们有多少内存?假设我们有可用的X MB内存。

  1. 将文件分为K个块,其中X * K = 2 GB。将每个块放入内存并使用任何O(n log n)算法照常排序。将行保存回文件。

  2. 现在将下一个块带入内存并排序。

  3. 完成后,请逐一合并。

  4. 上述算法也称为外部排序。步骤3称为N路合并 使用外部排序的基本原理是数据的大小。由于数据太大而我们无法将其全部存入内存,因此我们需要采用基于磁盘的排序算法。

    怀疑:

    当在步骤3中进行合并排序时,在比较2个数组时,每次比较时我们是否需要2 * X空间?限制是X MB。我们应该把块打成(X / 2)* 2K = 2GB吗?这样每个块将是X / 2 MB,并且将有2K块。或者我只是理解合并排序错误? 谢谢!

3 个答案:

答案 0 :(得分:9)

http://en.wikipedia.org/wiki/External_sorting

快速浏览维基百科告诉我,在合并过程中,你永远不会在内存中占据一大块。所以基本上,如果你有K块,你将有K个打开文件指针,但在任何给定时间你只能从内存中的每个文件中保留一行。您将比较内存中的行,然后将最小的行(例如,从块5)输出到已排序的文件(也是打开的文件指针,而不是内存中),然后用该文件中的下一行覆盖该行(在我们的示例中,将文件5)存入内存并重复,直到到达所有块的末尾。

答案 1 :(得分:6)

首先,第3步本身不是合并排序,整个事物是合并排序。第3步只是一个合并,根本不涉及任何排序。

至于所需的存储空间,有两种可能性。

第一种是将分类数据合并为两组。假设你有三组:

A: 1 3 5 7 9
B: 0 2 4 6 8
C: 2 3 5 7

使用该方法,您可以将AB合并到一个组Y,然后将YC合并到最终结果{{ 1}}:

Z

这具有非常小的常量内存要求的优点,因为您只需要存储两个列表中的每一个的“next”元素,但是,当然,您需要执行多个合并操作。

第二种方式是“正确的”N路合并,您可以从任何组中选择下一个元素。有了它,您将检查每个列表中的最低值,以查看下一个列表:

Y: 0 1 2 3 4 5 6 7 8 9         (from merging A and B).
Z: 0 1 2 2 3 3 4 5 5 6 7 7 8 9 (from merging Y and C).

这只涉及一次合并操作,但它需要更多存储空间,基本上每个列表只有一个元素。

您选择哪一项取决于可用内存和元素大小。

例如,如果您有100M内存可供使用且元素大小为100K,则可以使用后者。这是因为,对于2G文件,您需要20个组(每组100M)用于排序阶段,这意味着正确的N路合并将需要100K乘20或大约2M,远低于您的内存可用性。

或者,假设您只有1M可用。这将是大约2000(2G / 1M)组,并乘以100K给出200M,远远超出你的容量。

所以你必须在多次传递中进行合并。请记住,它不必是合并两个列表的多次传递。

你可以找到一个中间地带,例如每个通道合并十个列表。十组100K只是一个兆位,因此将适合你的内存约束,这将导致更少的合并传递。

答案 2 :(得分:2)

合并过程比这简单得多。您将把它们输出到一个新文件,但基本上您只需要常量内存:您只需要一次从两个输入文件中的每一个读取一个元素。