设计外存排序算法

Posted

技术标签:

【中文标题】设计外存排序算法【英文标题】:Designing an external memory sorting algorithm 【发布时间】:2016-08-31 22:27:54 【问题描述】:

如果我有一个非常大的列表存储在需要排序的外部存储器中。假设这个列表对于内存来说太大了,在设计外部排序算法时应该考虑哪些主要因素?

【问题讨论】:

什么样的外部存储器? 老实说,我只是使用 hadoop。它将所有数据存储在内存之外,并自动按键对键值对进行排序。在 Mapper 和 Reducer 之间。 我只是想知道你在创建算法时要考虑的主要因素是什么。例如。如果我不考虑数据的大小(其中“数据大小”是主要因素),我会遇到什么问题,这只是一个例子。我不是在寻找问题的具体解决方案。不过还是谢谢你的回答。 这个话题太宽泛,没有更具体的信息。无论如何,外部存储器通常要慢得多,因此您希望避免单独访问,而是使用块访问(将块移动到内部存储器做您的事情,并在完成后发回)。另一个问题是某些外部存储器(如 FLASH)的写入次数有限,因此您希望避免过多的重写。不知道使用的内存和接口硬件技术只是猜测,如果...... 这正是我想要的。使用块访问是一个需要考虑的因素,非常有效且有用。谢谢你。现在我只需要几个, 【参考方案1】:

在您构建自己的外部排序之前,您可能会查看操作系统提供的工具。 Windows 有 SORT.EXE,它在某些文本文件上运行良好,尽管它有……特性。 GNU 排序也很有效。您可以对其中的任何一个数据进行尝试,看看它们是否能满足您的需求。

否则。 . .

external sort 是一个非常知名的算法。总体思路:

    将尽可能多的数据加载到内存中。 对该块进行排序。 将该块写入外部存储器。 重复步骤 1-3,直到所有块都已排序和存储。 合并已排序的块。

假设您有n 项目被分成km 元素每个(所以n = k*m),第一部分(步骤1-4)花费的时间与k*(m log m )。

在完成步骤 1-4 后,您将拥有 k 已排序的 m 项目块(或者可能是 k-1m 项目,以及一个具有较少项目的块)。或者,如果您正在对字符串进行排序,您有 k 大小大致相同的块,但每个块中的字符串数量会有所不同。

您现在需要合并这些已排序的块。典型的做法是使用k-way merge。

您创建一个包含每个块的第一项的最小堆。然后从堆中选择根项,它是所有块中最小的项。您将其作为第一项输出。然后,从最小的块中读取下一项,并将其放在堆上。那就是:

create heap
for each block
    read item and add to heap
end for

while heap is not empty
    remove smallest item from heap
    write to output
    read next item from block that contained smallest item
    add to heap
end while

这部分算法是O(n log k),其中n是项目总数,k是块数。

正如其他人所指出的,有效的外部排序的一个关键是减少 I/O。外部存储。我上面描述的算法做尽可能少的 I/O。每个项目从外部存储读取两次,每个项目写入外部存储两次。其他乍一看更简单或更快的算法在处理真实数据时最终会慢得多,因为它们在 I/O 上花费了太多时间。

如果您对实现感兴趣,我在不久前写了一系列关于 sorting a very large text file 的文章。代码是 C#,但描述应该可以让您轻松翻译成任何语言。

【讨论】:

以上是关于设计外存排序算法的主要内容,如果未能解决你的问题,请参考以下文章

数据结构-排序算法

八大排序算法总结

八大排序算法及其比较

十大经典排序算法

python三级算法:排序——冒泡排序

转载8大排序算法