如何使用较少/较少的内存对文件中的数百万行数据进行排序

时间:2010-10-18 16:38:09

标签: algorithm

(来自here

我上周参加了一次采访,问了这个问题:

如何在基于8080处理器的计算机中仅使用640KB内存的文件中对十亿行数据进行排序?没有虚拟内存,没有外部磁盘。

我明确地询问了面试官我是否可以使用硬盘驱动器,因此我可以在排序树时对其进行序列化,然后在最后进行组合。他说不。我尝试了很多方法,不同的算法。他没有同意。

我放弃了,礼貌地问他,“你会怎么做?”他直言不讳地说:“我不会告诉你的。” (采访在那之后就结束了。我并不是冒犯他,作为一名开发人员,我很好奇。而且,这是一个本能的问题,正如我在工作场所会问任何人一样。)

这次采访是针对一家非常大的银行。

那么,怎么会有人解决这个问题?

9 个答案:

答案 0 :(得分:7)

Heapsort将是我的推荐。当n很大时,它相对较快,你只需要同时查看具有明确不同的三个元素。

话虽这么说,我的直觉告诉我,即使在C中,在8080上排序十亿行也不会慢得多。

答案 1 :(得分:6)

对于初学者,我不会在C#中这样做。你确定你有这个标签吗?如果可以解决,这是一个C问题。

640K只能给你640 * 1024 * 8位,所以无法解决这个问题。也许这就是他/她正在寻找的答案。这些投资银行的采访有时是一种思想游戏。

答案 2 :(得分:4)

如果不要求速度,则可以在文件中放置bubble sort行。这只需要一次查看两行数据,不需要外部信息或存储。

答案 3 :(得分:4)

另一个要问的问题是“行的性质是什么?”如果不同值的数量足够低,那么答案可能是pigeon hole sort

例如,假设要排序的文件仅包含保存0到100之间的数字的行。创建一个101个无符号32位或64位整数的数组,其值为0.当您读取一行时,使用它来索引数组并增加该元素的计数。读取文件后,从0开始,读取读取的零数并吐出多个,转到1,重复。根据需要扩展数组大小以处理通过的数字集。当然有一些限制,比如可以看到的值从-2e9到+ 2e9。这将需要4e9箱,这不适合640K的RAM。

如果相反的行是字符串,但你仍然在查看一组足够小的不同值,那么使用关联数组或哈希表来保存计数。

答案 4 :(得分:2)

Knuth在external sorting上有一整节;当没有硬盘驱动器时,这种情况很常见。没有太多的内存,磁带驱动器是常态。查看维基百科页面和/或第一卷。 Knuth的计算机编程艺术之三。

我同意Robusto的评论:

  

如果您无法使用该驱动器,您从何处获取该文件?它肯定不会留在记忆中。

问题定义不够。

答案 5 :(得分:2)

我越是想到这一点,我认为合并排序在我们给出的内存窗口中运行得越好。

假设您有x个可用内存。将十亿个条目划分为十亿/ x + 1个部分并对其进行处理(heapsort因为不需要额外的内存而且是O(2n(log n))时间)。当所有部分都被堆叠时,从所有部分的第一个元素开始进行合并排序。只要你有超过sqrt(十亿)的内存来使用给定的基本8080 OS内存使用,这就可以工作。

进行数学运算时,假设每个数据行少于165位。

答案 6 :(得分:2)

显然你必须能够读取和写入十亿行文件。没有外部磁盘的约束意味着您必须将自己限制为就地算法或对数据的起始条件和分布做出一些假设,以便您可以在将数据添加到文件时对数据进行排序(例如,使用密钥作为索引并创建一个足够大的文件来保存预期的键数。)

如果必须以未排序的文件开头并对其进行排序,则可以使用合并在文件的非常小的块上运行的就地合并排序。由于没有对存储介质的访问时间进行限制,因此可能非常快。

答案 7 :(得分:0)

我会使用GPU!即使在快速计算机上,the GPU is often faster at sorting也是如此。而且我不知道“行”有多大,但是找到1GB的显卡并不难,所以这也解决了存储问题。

此外,如果我不得不在8080上工作,我肯定想把最好的显卡放在那里。

您必须为后续问题做好准备:“如何让8080与现代PCI Express 2.0 x16卡通话?”。我发现了一种真正奇妙的方法,但这个文本区域太窄而无法容纳它。

答案 8 :(得分:0)

您可以在Jon Bentley 编程珍珠 Column. 1.中找到关于类似问题的讨论。这里Bentley处理数百万区域代码的排序问题,这些区域代码保证是唯一的通过使用bitset数据结构。