转自:http://www.2cto.com/kf/201307/225189.html
内排序算法我们学了很多,快速排序、冒泡排序等。这些排序的前提是数据量不大,能够全部读进内存里。外排序是指对大数据量进行排序,数据量大到不能全部读进内存里,必须在内存和外存间换进换出进行排序。
最常用的外排序法是归并法。举个例子,对900M的数据进行外排序,但内存只有100M。排序过程:
1、将原数据分组进行排序,每组100M,一共9组。 排序过程是读100M进内存,对这100M进行内排序(用快速排序等),然后输出到外存的一个临时文件。接下来读下一个100M。
2、步骤1产生了9个排好序的临时文件。将100M内存分为10个10M的buffer,其中9个作为9个输入文件的buffer,另外一个10M内存作为输出buffer,然后做9路归并排序。
回想一下以前学的内排序中的归并排序,与归并法外排序做比较。 发现他们差别是:
1、内排序中的归并排序是两个两个做归并组成一个大的有序数组然后接着和大数组进行归并。
2、外排序中的归并排序做9路归并,一次性归并完。
这种做法的好处是减少对硬盘的读写次数。多路归并时对每一个数据只进行一次硬盘读写,若是像内排序中的归并那样直要有多次的读写硬盘。 谨记,现代计算机中的程序,瓶颈基本上是在IO,而不在于CPU。
事实上,这里有一个问题需要权衡。太多路同时进行归并也会有问题。我们的例子中,输入buffer每次可以读取10M的数据。但如果数据真的特别大,以至于多路归并时内存分了太多个buffer,导致每个buffer很小每次只能读入很小的数据比如说1K,这种情况性能也会大大降低的。这时候就需要做多次的归并,比如说对于1个100G的输入数据,可以一个G一个G的做归并外排序然后存到外存临时文件里,然后再对这10个G做一个10路归并。
当对数据记录量巨大的数据文件进行排序时,由于受到内存容量的限制,无法将所有数据记录一次全部读入到内存进行。排序过程中需要多次进行内、外存之间的数据交换。利用外存对数据文件进行排序称为外部排序。
外部排序最基本的方法是归并。这种方法是由两个相对独立的阶段组成:
① 按内存(缓冲区)的大小,将n个记录的数据文件分成若干个长度为l的段或子文件,依次读入内存并选择有效的内部排序方法进行排序;然后将排好序的有序子文件重新写入到外存。子文件称为归并段或顺串。
② 采用归并的办法对归并段进行逐趟归并,使归并段的长度逐渐增大,直到最后合并成只有一个归并段的文件—排好序的文件。
1 外部排序的简单方法
归并排序有多种方法,最简单的就是2-路归并。
设有一个磁盘上的数据文件,共有100,000个记录(A1, A2,…,A100000),页块长为200个记录,供排序使用的缓冲区可提供容纳1000个记录的空间,现要对该文件进行排序,排序过程可按如下步骤进行:
第一步:每次将5个页块(1000个记录)由外存读到内存,进行内排序,整个文件共得到10个初始顺串R1~R10 (每一个顺串占5个页块),然后把它们写回到磁盘上去。
第二步:然后两两归并,直到成为一个有序文件为止。
由图可知,每趟归并由m个归并段得到┌m/2┐个归并段。
2 外排序的时间分析
外排序的时间消耗比内排序大得多,原因是:
● 外排序的数据量(记录)一般很大;
● 外排序涉及到内、外存之间的数据交换操作;
● 外存的操作速度远远比内存中的操作慢。
外排序的总时间由三部分组成:
外排序的时间=产生初始归并段的时间(内排序)m×tis
+I/O操作的时间d×tio
+内部归并的时间s×utmg
其中:
m:初始归并段数目;tis:得到一个归并段的内排序时间;
d:总的读、写次数;tio:一次读、写的时间;
s:归并的趟数;utmg:对u个记录进行一趟内部归并排序的时间。
一般地,tio>>tis,tio>>tmg,tio而取决于所用外存,因此,影响外排序效率的主要原因是内、外存之间数据交换(读、写外存)。提高效率的主要方法(途径)有:
● 进行多路归并,减少文件归并的趟数;
● 增加归并段的长度,减少初始归并的数目;
● 根据不同归并段的长度,采取最佳归并方案。