有效合并排序文件?

时间:2015-09-29 11:59:34

标签: algorithm

我有n个文件,50 <= n <= 100包含已排序的整数,所有这些文件大小相同,只有2​​50MB或500MB。

例如

1st file: 3, 67, 123, 134, 200, ...
2nd file: 1, 12, 33, 37, 94, ...
3rd file: 11, 18, 21, 22, 1000, ...

我在4核机器上运行它,目标是尽快合并文件。

由于总大小可以达到50GB,我无法将其读入RAM。

到目前为止,我尝试执行以下操作:

1) Read a number from every file, and store them in an array.
2) Find the lowest number.
3) Write that number to the output.
4) Read one number from the file you found the lowest before (if file not empty)

重复步骤2-4,直到我们没有数字。

使用4MB的缓冲区进行读写。

我上面的算法工作正常,但它没有像我想要的那样快。最大的问题是,如果我有100个文件x 250MB而不是50个文件x 500MB,则表现最差。

在我的案例中,最有效的合并算法是什么?

3 个答案:

答案 0 :(得分:5)

嗯,您可以通过改进算法中的步骤(2)来明智地提高效率。而不是对所有数字进行线性搜索,使用最小堆,任何插入和删除堆中的最小值都是在对数时间内完成的,因此它将提高大量文件的速度。这会将时间复杂度更改为O(nlogk),超过原始O(n*k)(其中n是元素总数,k是文件数)

此外,您需要最大限度地减少文件中“随机”读取的次数,因为很少的连续大读取比许多小型随机读取快得多。例如,你可以通过增加缓冲区大小来实现这一点(写作也是如此)

答案 1 :(得分:1)

(java)使用GZipInputStream和GZipOutputStream进行.gz压缩。也许这会在一定程度上允许内存使用。使用快速而不是高压缩。

然后应该减少磁盘上几个文件的移动,比如更多的文件合并2个文件,这两个文件都是较大的序列。

对于重复,可以使用&#34; run-length-encoding&#34; - 而不是重复,添加重复计数:11 12 13#7 15

答案 2 :(得分:1)

利用多个核心的有效方法可能是在主要比较线程的不同线程中执行输入和输出,这样所有核心都保持忙碌,主线程永远不会不必要地阻塞输入或输出。一个线程执行核心比较,一个写入输出,NumCores-2处理输入(每个来自输入文件的子集)以保持主线程的馈送。

输入和输出线程还可以执行特定于流的预处理和后处理 - 例如,根据输入数据的分布,@ Joop提到的类型的运行长度编码方案可能提供显着的加速通过允许它有效地排序整个输入范围的主线程。

当然,所有这些都会增加复杂性和错误的可能性。