我有一个包含大量数据的文件,我希望在任何给定时间对其中的一小部分数据进行排序。
我注意到合并排序很受外部排序的欢迎,但我想知道它是否可以用堆来完成(最小或最大)。基本上我的目标是在100个项目列表中获得10个项目的顶部(使用任意数字),而从不在内存中保存超过10个项目。
我主要理解堆积,并且理解堆积数据会使其按照适当的顺序排列,我可以从中获取最后一部分作为我的解决方案,但我无法弄清楚如何处理每个freakin'项目的I / O.
想法?
谢谢! :d
答案 0 :(得分:4)
使用heapsort需要在文件中进行大量的搜索操作,以便最初创建堆,并在删除顶部元素时使用。出于这个原因,这不是一个好主意。
但是,您可以使用mergesort的变体,其中每个堆元素都是一个排序列表。列表的大小取决于您希望在内存中保留多少。您可以通过加载数据块,对它们进行排序然后将它们写入临时文件来从输入文件创建这些列表。然后,将每个文件视为一个列表,读取第一个元素并从中创建堆。删除顶部元素时,将其从列表中删除,并在必要时恢复堆条件。
虽然有一个方面可以使这些关于排序不相关的事实:你说你想确定前10个元素。为此,您确实可以使用内存堆。只需从文件中取出一个元素,将其推入堆中,如果堆的大小超过10,则删除最低元素。为了提高效率,如果大小低于10或者高于最低元素,则只将其推入堆上,然后替换并重新堆积。将前十名保留在堆中允许您只扫描文件一次,其他所有内容都将在内存中完成。使用二叉树而不是堆也可以工作,并且可能同样快,对于像10这样的小数字,你甚至可以使用数组并对元素进行起泡。
注意:我假设10和100只是例子。如果你的数字真的那么低,那么关于效率的任何讨论都可能没有实际意义,除非你每秒进行几次这样的操作。
答案 1 :(得分:2)
是的,你可以使用堆来查找大文件中的top - k
项,只保留堆+内存中的I / O缓冲区。
以下将通过使用长度为k
的最大堆来获取min - k
项。您可以顺序读取文件,为每个项目执行I / O操作,但将块中的数据加载到长度为b
的辅助缓冲区中通常要快得多。该方法使用O(n*log(k))
空格在O(k + b)
操作中运行。
while (file not empty)
read block from file
for (i = all items in block)
if (heap.count() < k)
heap.push(item[i])
else
if (item[i] < heap.root())
heap.pop_root()
heap.push(item[i])
endif
endfor
endwhile
答案 2 :(得分:0)
堆需要大量非顺序访问。 Mergesort非常适合外部排序,因为它可以进行大量的顺序访问。
由于磁头不需要移动,顺序访问在旋转的磁盘类型上要快得多。在固态磁盘上顺序访问可能比heapsort的访问速度快得多,因为它们访问的块可能比文件中的单个块大得多。
答案 3 :(得分:-1)
通过使用Merge sort并通过引用传递这两个值,您只需将两个比较值保存在缓冲区中,然后在整个数组中移动,直到它就地排序。