一般来说,对一个数组的排序,我们常用冒泡排序、快速排序、堆排序等算法进行排序。这样的数组能够一次性加载到内存中,使用上述的排序算法就能轻而易举进行排序,所以上述的排序算法可以称之为堆内排序。
然而有些场景下,一个待排序的文件可能超过甚至远远大于应用程序的运行内存。这种情况,一次性将文件加载到内存中,明显是不可行的,需要使用其他的排序手段进行排序。外部排序就是一种可行的方案。
基本思想
1、将原文件拆分成一个个能一次性加载到内存的小文件
2、依次将小文件排序
3、将排好序的小文件归并成一个有序的大文件
归并的方法
二路归并
各片段均已采用内排序算法进行排序,每次读入2路有序片段的前m个元素进行归并;若输出缓冲区已满,则将已归并好的元素写入文件;若其中一路m个元素归并完成,读入该路剩下的前m个元素。重复交替执行,直到所有元素都归并完成为止
缺点:元素需要反复比较,比较次数过多,导致归并的效率很低。
k路归并
基于二路归并多次比较的缺点,有人提出了改进算法,采用多路归并来提高效率。
k路归并可以使用堆进行排序,利用完全二叉树的性质,可以很快更新,保持堆的性质。但是,操作次数不够精简。
胜者树
归并过程:
1、在拆分成k个文件并排序后,取每个文件的首个元素作为叶子节点,构建一颗败者树
2、输出一个最值到缓冲区;如果缓冲区已满,则将数据写入文件
3、从输出的值对应的来源文件取元素,加入到胜者树中,同时调整树
4、重复第2、3步骤,直到所有数据都读取并归并,最终得到排序的文件
败者树将败者存放在父结点中,而胜者再与上一级的父结点比较。败者树的更新只需将子节点与父节点比较。