如何将数据添加到一堆已排序的文件中

时间:2013-03-14 13:14:03

标签: algorithm sorting external-sorting

如果之前已经重复过,我道歉,但我找不到任何有关我选择的措辞的帖子。我正准备接受采访,而且我一直在阅读外部排序。例如,如果要对多个32位整数的硬盘进行排序,可以进行计数排序并使用64位计数器来计算32位整数。然后,在每个可能的32位整数值处,您将有一个表示它的计数器。您也可以对类似事物使用外部合并排序,取O(nlogn)时间而不是O(1)时间。但是,我一直在考虑一个可能很常见的案例,但我想不出最好的方法 - 将新数据添加到可能跨越许多硬盘的一堆排序文件中。

如果数据存储在内存中,可以使用堆(优先级队列)在logn时间内完成此插入。但是,我们无法从硬盘空间创建堆。使用列表,您必须使用O(logn)搜索来查找数据的位置(用于二进制搜索,排序),然后向后或向前冲击其余数据,或者您可能不必根据实现移动任何内容容器(数组,链表等)。然而,在硬盘世界中,读取和写入比在RAM中要昂贵得多,因此在某处插入数据然后移动(重写)其余数据似乎非常昂贵。有没有任何技巧可以推荐给我?我很乐意读自己,我找不到正确的方法来提出我的问题以找到任何信息。谢谢!

3 个答案:

答案 0 :(得分:2)

如果你在这里(或其他地方)查找“外部排序”,你会发现你所描述的内容的讨论。外部排序也是一个标签。

  

在硬盘世界中,读写更多   比在RAM中昂贵,所以在某处插入数据然后移位   (重写)其余数据似乎过于昂贵。

外部排序适用于具有足够内存(或在大多数情况下足够'每个进程)内部执行此操作的情况。数据集太大而不能一次保存在内存中并不罕见。因此,您接受I / O绑定排序的较高运行时成本。

答案 1 :(得分:2)

我说要读取您的已排序数据的文件,读取您想要排序并添加到那里的文件,扣紧计数器并用新计算的文件覆盖已排序的数据文件。直接读取在现代磁盘系统上比随机读取要便宜得多,无论如何你都需要找到每个int的位置,因此整个卷的单个顺序读取将比单个扇区的~32次读取耗时更少每个要排序的文件的数量。

另外,我会说排序32位整数最好用已经以计数器形式出现的结果,特别是像“几个硬盘”这样的超大规模,你几乎每个桶都会有至少1个在32位空间中,所以存储64位* 2 ^ 32可能小于2 ^ 33 32位零然后2 ^ 32那么...

答案 2 :(得分:1)

如果内存中有空间来容纳文件,并且你有一组最小元素为k的数字,那么你将不得不重写文件中大于k的所有数字。没有办法解决这个问题。他们都必须转移至少一个职位。

如果您希望利用大部分数组已经排序的事实,并且您在内存中有足够的空间来执行此操作,那么对插入的元素进行排序并将其与大于其最小的元素列表合并成员是一个很好,快速的方法来做到这一点。 EG:

DISK:

1 2 3 4 5 6 8 10 11 12

插入:9 7 13

对插入进行排序:

7 9 13

在磁盘上查找适用的已排序列表的子集: 8 10 11 12

合并元素(如Mergesort:)

7 8 9 10 11 12 13

将它们复制回磁盘:

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

另一方面,如果您的内存空间远小于列表的总大小,则建议使用其他技术。例如:

1 2 3 4 .. 1000 1002 1003 ... 999,998,1,000,000 ......

作为磁盘上的列表和

1001,999,999

作为您的插入。在这种情况下,您需要遍历每个元素,计算插入列表中小于该元素的元素数,然后执行此操作。在这个简单的例子中,天真的计数器非常快 - 你可以看到1,000,0000需要两次跳跃。如果插入的数量可能比较大,您可以对插入进行排序,然后对此元素使用二进制搜索来查找较大数组中每个元素可能位于的位置。这将为您提供有关可以复制的项目数的信息。因此,顶部的相应跳跃值将是:

0 0 0 0 ... 0 1 1 ... 1 2

希望您能看到一个相当明显的方法,您可能希望决定将其中一个插入元素写入磁盘。