外排序

外排序（External sorting）是指能够处理极大量数据的排序算法。通常来说，外排序处理的数据不能一次装入内存，只能放在读写较慢的外存储器（通常是硬盘）上。外排序通常采用的是一种“排序-归并”的策略。在排序阶段，先读入能放在内存中的数据量，将其排序输出到一个临时文件，依此进行，将待排序数据组织为多个有序的临时文件。而后在归并阶段将这些临时文件组合为一个大的有序文件，也即排序结果。

外归并排序
外排序的一个例子是外归并排序（External merge sort），它读入一些能放在内存内的数据量，在内存中排序后输出为一个顺串（即是内部数据有序的临时文件），处理完所有的数据后再进行归并。比如，要对900 MB的数据进行排序，但机器上只有100 MB的可用内存时，外归并排序按如下方法操作：
 读入100 MB的数据至内存中，用某种常规方式（如快速排序、堆排序、归并排序等方法）在内存中完成排序。
 将排序完成的数据写入磁盘。
 读入每个临时文件（顺串）的前10 MB（ = 100 MB / (9块 + 1)）的数据放入内存中的输入缓冲区，最后的10 MB作为输出缓冲区。（实践中，将输入缓冲适当调小，而适当增大输出缓冲区能获得更好的效果。）
 执行九路归并算法，将结果输出到输出缓冲区。一旦输出缓冲区满，将缓冲区中的数据写出至目标文件，清空缓冲区。一旦9个输入缓冲区中的一个变空，就从这个缓冲区关联的文件，读入下一个10M数据，除非这个文件已读完。这是“外归并排序”能在主存外完成排序的关键步骤 -- 因为“归并算法”(merge algorithm)对每一个大块只是顺序地做一轮访问(进行归并)，每个大块不用完全载入主存。

为了增加每一个有序的临时文件的长度，可以采用置换选择排序（Replacement selection sorting）。它可以产生大于内存大小的顺串。具体方法是在内存中使用一个最小堆进行排序，设该最小堆的大小为。算法描述如下：
 初始时将输入文件读入内存，建立最小堆。
 将堆顶元素输出至输出缓冲区。然后读入下一个记录：
 若该元素的关键码值不小于刚输出的关键码值，将其作为堆顶元素并调整堆，使之满足堆的性质；
 否则将新元素放入堆底位置，将堆的大小减1。
 重复第2步，直至堆大小变为0。
 此时一个顺串已经产生。将堆中的所有元素建堆，开始生成下一个顺串。

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

附加的步骤
上述例子的外排序有两个步骤：排序和归并。我们用一次多路归并就完成了所有临时文件的归并，而并非按内存中的二路归并那样，一次归并两个子串，耗费次归并。外排序中不适用上述方法的原因在于每次读写都需要对硬盘进行读写，而这是非常缓慢的。所以应该尽可能减小磁盘的读写次数。

不过，在上述方法中也存在权衡。当临时文件（顺串）的数量继续增大时，归并时每次可从顺串中读入的数据减少了。比如说，50 GB的数据量，100 MB的可用内存，这种情况下用一趟多路归并就显得不划算。读入很多的顺串花费的时间占据了排序时间的大部分。这时，我们可以用多次（比如两次）归并来解决这个问题。

这时排序算法变为下述这样：
 第一步不变。
 将小的顺串合并为大一些的顺串，适当减小顺串的数目。
 将剩余的大一些的顺串归并为最终结果。

和内排序一样，高效的外排序所耗的时间依然是。若利用好现在计算机上GB的内存，可使时间复杂度中的对数项增长比较缓慢。

优化性能
计算机科学家吉姆·格雷的Sort Benchmark网站用不同的硬件、软件环境测试了实现方法不同的多种外排序算法的效率。效率较高的算法具有以下的特征：

 并行计算
 用多个磁盘驱动器并行处理数据，可以加速顺序磁盘读写。
 在计算机上使用多线程，可在多核心的计算机上得到优化。
 使用异步输入输出，可以同时排序和归并，同时读写。
 使用多台计算机用高速网络连接，分担计算任务。
 提高硬件速度
 增大内存，减小磁盘读写次数，减小归并次数。
 使用快速的外存设备，比如15000 RPM的硬盘或固态硬盘。
 使用性能更优良个各种设备，比如使用多核心CPU和延迟时间更短的内存。
 提高软件速度
 对于某些特殊数据，在第一阶段的排序中使用基数排序。
 压缩输入输出文件和临时文件。

其他算法
外归并排序法并不是唯一的外排序算法。另外还有外分配排序，其原理类似于内排序中的桶排序。在归并排序和桶排序之间存在数学上的某种对偶性。此外还有一些不耗费附加磁盘空间的原地排序算法。

外部链接
STXXL,一个包含外归并排序的代码包
外归并排序示例
多路归并实现
Java语言外归并排序

参考

排序算法