由于内存空间小,对于存储在硬盘上的数据进行排序要用到外部排序。
一个简单的外部排序思路是:将硬盘上的大数据分段进行内部排序,结果得到n个排好序的归并段(顺串),然后再对这些归并段进行归并排序。假设用k路归并排序,则需要进行趟归并。
硬盘上的数据是按块存储的,归并过程中按块读取数据(假设有10000条记录,硬盘每块可存储200条记录,则初始化成归并段需要50次读硬盘操作,50写硬盘操作,之后每趟归并操作需要50次读硬盘操作,50次写硬盘操作)。
一般情况下,外部排序所需总的时间=内部排序(产生初始归并段)所需时间(m×t_IS)+外部信息读写的时间(d×t_IO)+内部归并所需的时间(s×ut_mg),其中,t_IS是得到一个初始归并段进行内部排序所需的时间均值;t_IO是进行一次外存读/写(这里一次外存读写指读写硬盘一个块儿)时间均值;ut_mg是对u个记录进行内部归并所需时间;m为经过内部排序之后得到的初始归并段的个数;s为归并的趟数;d为总的读/写次数。显然,t_IO较t_mg要大得多,因此提高外排的效率应主要着眼于减少外存信息读写的次数d。其中,m、t_IS、t_IO几项是不变的,总的读写次数d随归并趟数的增加而增加,而归并趟数随着归并路数(几路归并)的增加而减小,所以总的硬盘读写次数d随归并路数k的增加而减小。
若用k路归并,则每得到有序串的下一个元素,若按传统的归并方法,则需要(k-1)次比较(找到k个元素中的最小值),所以单纯增加k将导致增加内部归并的时间ut_mg。假设所得初始归并段为m个,则内部归并过程中进行比较的总时间为:,等价于,归并趟数×每得到下一个有序元素所需要的比较次数×总的元素个数×每次两个数比较的时间开销。但是假设用败者树的方法进行k路归并,则没得到下一个有序元素所需要的比较次数可降低为
,则内部归并过程中进行比较的总时间可降低为:
,即降低为一个与k无关的式子。不过,k值的选择并非越大越好,如何选择合适的k是一个需要综合考虑的问题。
败者树:http://blog.sina.com.cn/s/blog_8b745a5f010159vz.html
归并趟数位。可以看出归并趟数不仅和k有关,还和初始归并段的数目n有关,初始归并段的数目n越小,归并趟数越少。总的数据记录的数目是一定的,所以当初始归并段的长度越长时,初始归并段的数目越小。一般的归并排序,所需内存空间最小为O(l)(l为初始归并段的长度),所以这样就限制了初始归并段的数目的减小。针对这一问题,有一种方法,就是在创建初始段的时候用“置换——选择排序”。这样可以让初始归并段的平均长度提高到原来的2倍。“置换——选择排序”可以参考一下链接:
置换——选择排序:http://blog.sina.com.cn/s/blog_8b745a5f01015co2.html