超出RAM大小的数据排序

13
这是一道谷歌面试题: 有两台机器,每台机器都有64GB的RAM,其中包含所有整数(8字节),请对整个128GB数据进行排序。您可以假设有少量额外的RAM。请扩展该问题以对存储在1000台机器中的数据进行排序。
我想到了外部排序。我们将整个数据分成多个块,并对它们使用归并排序。也就是先对这些块进行排序,然后将它们放回去,并逐个将它们取出来合并。是否有更好的方法?复杂度会是多少?

分割,重新合并。是否可能避免单个机器进行最终合并?是的:基数排序。 - wildplasser
@wildplasser - 这并不重要。合并比外部I/O更快,因此合并过程仅限于将128GB数据写入目标驱动器所需的时间。使用n+1个设备,可以使用n路合并来写入剩余的驱动器。这将允许n台机器并行在n个工作驱动器上创建n个数据块,但最终合并受目标驱动器的I/O速度限制。 - rcgldr
你可以考虑共享文件系统为一个(单一的)机器。但这仍然会是一个瓶颈锁。 - wildplasser
3个回答

4

ChingPing提出了一种O(n log n)的排序方法,对每个子集进行排序,然后通过交换元素进行线性合并。Quicksort(以及大多数n log n排序算法)的问题在于它们需要n的内存。我建议改用SmoothSort,它使用常量内存,仍然以O(n log n)的速度运行。

最坏情况是这样的:

setA = [maxInt .. 1]
setB = [0..minInt]

两个集合都是按照相反的顺序排序,但是合并的顺序是相反的。

ChingPing的解决方案(在我看来更加清晰明了)是:

Have a pointers 'pointerA', 'pointerB' initialized at the beginning of each array
While setA's pointer is not at the end
  if (setA[pointerA] < setB[pointerB])
    then { pointerA++; }
    else { swap(setA[pointerA], setB[pointerB]); pointerB++; }

现在这两个集合都应该已经排序。


1
快速排序的问题在于需要n个内存,即使是最坏情况也是如此,参见Sedgewick变体(先对非较大的分区进行排序)。 - greybeard
线性合并通过交换元素似乎不起作用。考虑这种情况,setA = {0, 1, 6, 7},setB = {2,3,4,5}。在线性合并之后,结果是setA = {0, 1, 2, 3},setB = {6, 7, 4, 5}。问题在于,如果setA中的一个元素> setB中的一个元素,则需要对setB执行类似插入排序的操作,其时间复杂度为O(n^2)。 - rcgldr

0

2台机器情况下已经有答案。

我假设要排序的128GB数据存储在单个硬盘(或任何外部设备)的单个文件中。无论使用多少台机器或硬盘,读取原始的128GB文件和写入排序后的128GB文件所需的时间都是相同的。唯一的节约发生在基于内存的排序过程中,以创建排序后的数据块。将n+1个硬盘合并为单个排序后的128GB文件所需的时间仍然相同,受限于将128GB排序文件写入剩余硬盘所需的时间。

对于n台机器,数据将被分成128GB/n个块。每台机器可以交替读取子块,例如每次64MB,以减少随机访问开销,以便“最后”一台机器在其他所有机器读取其块之前开始工作。

对于n台机器(每台64GB内存)和n+1个硬盘,其中n≥4,每台机器可以使用O(n)时间复杂度的基数排序同时在n个工作硬盘上创建32GB或更小的块,然后进行n路合并到目标硬盘上。
随着n的增加,收益递减的点会限制更大的n带来的好处。当n > 16时,内部合并吞吐量可能会超过磁盘I/O带宽。如果合并过程是CPU绑定而不是I/O绑定,则存在一种权衡,即在并行创建块所需的CPU开销与合并开销大于I/O时间之间进行权衡。

据我理解这个问题,我们不应该使用硬盘,并且要排序的总数据量是n*64 GB,其中n是机器的数量。 - ruakh
@ruakh - 如果每台机器都有64GB,那么排序前后的128GB数据存储在哪里? - rcgldr
排序之前:随意分布在各个主机之间。排序之后:有序地分布在各个主机之间。 - ruakh
@ruakh - 这个问题陈述并不清楚。OP和我假设涉及到外部存储。如果没有的话,那么问题陈述就没有解释数据如何在机器之间传输。 - rcgldr

0

可以使用快速排序将每个64 GB单独排序,然后使用外部存储器在两个64GB数组的头部保留指针。假设我们希望按顺序在RAM1和RAM2中拥有整个数据,请继续递增RAM1上的指针(如果它小于RAM2上的指针值),否则交换该值与RAM2,直到指针达到RAM1的末尾。

采用相同的概念对所有N个RAM进行排序。取出它们的一对并使用上述方法进行排序。您将剩下N/2个已排序的RAM。以相同的概念递归地使用上述方法。


1
在每次递归中,取机器对的算法是什么? - Dialecticus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接