外排序:External Sort

今天在学习 "页面标签框架 display:table"是遇到了一个语句:sort = "external" ,就是外排序。

外排序是一个解决了对billlions of integers进行排序的算法。 引入外排序这个词,是因为相比于外排序, 我们之前学的内排序(internal sort), 就是能够在计算机的内存中直接完成排序任务的算。 7大内排序如下(只不过不同的perspective):

(1)bubber sort 

(2)Insertion sort

(3)quick sort

(4)heap sort

(5)merge sort

(6)radix sort

(7)selection sort

我们知道, 对于几百万个ints进行排序, okay, 你不用担心你的栈内存, 你的电脑内存足以应对。 但是当你有billions of numbers的时候, 例如10 billion, 此时你的电脑就可能crash掉了。 那么如何排序呢??? 解决办法就是采用divide and conquer!! 这就是外排序的思想所在。

好了, 既然你的数据量太大了, 无法一次性的装入内存, 只能放在外存储器中(通常是硬盘)。 外排序通常采用的策略就是 排序------归并。 在排序阶段, 先读入能够放在内存中的数据量,  然后将排序输出到一个临时的文件中, 依次进行下去, 最终我们获得多个有序的临时文件。 然后归并阶段将这些临时文件合并成一个大的有序的文件, 也即我们排序结果。 done!!!  下面说说关于排序, 归并这两个步骤的实现的具体细节。

举个例子, 假如我们有900MB的数据, 但是我们的可用内存为 100MB的时候, 外排序的方法如下:

(1)读入100MB数据至内存中, 对这100MB的数据进行排序。 排序算法有很多种, 可以选择quick sort, merge sort, 或者heap sort 等。 

(2)将排序完成的数据写入磁盘中的临时子文件。

(3)重复上述两个步骤, 最终我们得到9个临时文件, 每个临时文件的大小当然也是100MB,

(4)读入这9个临时文件的每个前10MB, 有9个, 所以我们总共读入了90MB的数据至内存中。 但是, 我们还需要额外的10MB, 这10MB是作为输出缓存的。

因为我们需要至少10MB的缓冲区用于存放读入的数据。 实践中, 我们需要适当的增大缓冲区的大小, 以便获得更好的效果。

(4)接下来,  好了, 我们需要执行9路数据的归并算法, 将结果输出到输出缓冲区。 一旦输出缓冲区满, 就将数据写入目标文件中, 清空缓冲区。 一旦9个输入缓冲区中有一个变空, 就从与这个缓冲区关联的文件中读入下一个10MB的数据。 除非这个文件已经变空了(即该文件数据过一遍了)。

为了增加每一个临时文件的程度(总共9个), 我们可以采用置换选择排序, 他可以产生大于内存大小的顺串。 具体方法是内存中使用最小堆进行排序。 设该最小堆的大小为M。 算法描述如下:

  1. 初始时将输入文件读入内存,建立最小堆。
  2. 将堆顶元素输出至输出缓冲区。然后读入下一个记录:
    1. 若该元素的关键码值不小于刚输出的关键码值,将其作为堆顶元素并调整堆,使之满足堆的性质;
    2. 否则将新元素放入堆底位置,将堆的大小减1。
  3. 重复第2步,直至堆大小变为0。
  4. 此时一个顺串已经产生。将堆中的所有元素建堆,开始生成下一个顺串。

此方法能生成平均长度为2M的顺串,可以进一步减少访问外部存储器的次数,节约时间,提高算法效率。


和高效的内排序一样, 高效的外排序的算法的时间复杂度为O(n log n)

曹永达

发表评论 取消回复