薛磊 Job Seeker

数据结构——9.外排序

2019-04-07

九、外排序

9.1 外排序概述

1、什么是外排序

​  外排序是指数据存放在外存中,数据排序时涉及内、外存数据交换的排序方法。

​  存储在外存上的数据以文件为基本单位。

2、外排序的基本方法

​  外排序的基本方法时归并排序法。它分为以下两个步骤:

​  (1) 生成若干初始归并段(顺串):这一过程也称为文件预处理。一种常规的方法如下:

​    ① 把含有n个记录的文件,按内存大小w分成若干长度为w的子文件(归并段);

​    ② 分别将各子文件调入内存,采用有效的内排序方法排序后送回外存,产生n/2↑个初始归并段。

​  (2) 多路归并:对这些初始归并段进行多遍归并,使得有序的归并段逐渐扩大,最后在外存上形成整个文件的单一归并段,也就完成了这个文件的外排序。

​  详细的过程见PPT。

​  归并过程的性能与 记录读写次数、内存中归并时需要关键字比较次数 有关。

​  外排序方法与各种外存设备的特征有关。

​  外存设备大体上可分为两类:

​    - 顺序存取设备,例如磁带。

​    - 直接存取设备,例如磁盘。

9.2 磁盘排序

9.2.1 生成初始归并段

​  另一种方法:采用一种称为 置换–选择 排序方法用于生成初始归并段。

​  置换–选择排序方法:

(1)从待排文件Fin中按内存工作区WA的容量w读入w个记录。设归并段编号i=1。
(2)使用败者树从WA中选出关键字最小的记录Rmin。
(3)将Rmin记录输出到Fout中,作为当前归并段的一个成员。
(4)若Fin不空,则从Fin中读入下一个记录x放在Rmin所在的工作区位置代 替Rmin。
(5)在工作区中所有≥Rmin的记录中选择出最小记录作为新的Rmin,转 (3),直到选不出这样的Rmin。
(6)设i=i+1,开始一个新的归并段。
(7)若工作区已空,则初始归并段已全部产生;否则转(2)。

置换–选择排序中关键字比较次数分析:

​  共有n个记录,内存工作区WA的容量为w:

​  - 若在w各记录中选取最小关键字采用简单比较方法,每次需要w-1次比较。

​  - 总的时间复杂度为O(nw)。

9.2.2 多路平衡归并

1、k路平衡归并概述

(1) 什么是k路平衡归并

​  2路平衡归并:每一趟从m个归并段得到m/2↑个归并段。

​  一般地,2路平衡归并的前提:初始归并段的记录个数都相同。→可以推广到k路平衡归并

(2) 影响k路平衡归并的因素

​  影响k路平衡归并效率的因素:

​    - 归并时需要读写磁盘的次数

​    - 归并时需要关键字比较的次数

(3) k路平衡归并时读写磁盘次数的计算

​  例如,m=8,假设每个归并段4个记录,k=2。

​  读记录次数=WPL=8*4*3=96.(如果每个记录占用一个物理块,读写磁盘次数=96*2=192次)

​  采用k路平衡归并时,通常k越大,读写磁盘次数会减少。

(4) k路平衡归并时关键字比较次数的计算

结论:

​  增大归并路数k,读写磁盘次数减少,而关键字比较次数会增大。若k增大到一定的程度,就会抵消掉由于减少读写磁盘次数而赢得的时间,

2、利用败者树实现k路平衡归并过程

​  败者树用于在k各记录中选取最小关键字的记录。败者树类似于堆排序中的堆。

​  利用败者树实现k路平衡归并的过程是:

​    - 先建立败者树,每个叶子结点对应一个归并段。(详细步骤及图示见PPT)

​    - 然后对k个输入有序段进行k路平衡归并。

​  调整产生冠军(最小值)的过程:将当前节点的关键字与父节点比较,将大的(败者)放在父节点中,小者(胜者)继续进行,直到根节点。最后将胜者放在冠军节点中。然后将冠军放入文件中,取其所在归并段下一个元素之前步骤。

结论:

​  关键字比较次数与k无关 → 总的内部归并时间不会随k的增大而在增大。

​  利用败者树实现k路平衡归并。

​  只要内存空间允许,尽可能增大归并路数k。

采用败者树,置换–选择排序中关键字比较次数分析

共有n个记录,内存空间WA的容量为w:

​  - 若在w各记录中选取最小关键字的采用败者树方法,每次需要log2 w 次比较。

​  - 总的时间复杂度为O(nlog2 w)。

9.2.3 最佳归并树

​  最佳归并树(m个初始归并段)是带权路径长度最短的k叉 (阶)哈夫曼树,构造步骤如下:

​  (1) 若x=(m-1) Mod (k-1)≠0,则需附加(k-1)-x个虚段,以使每次归并都可以对应k个段。

​  (2) 按照哈夫曼树的构造原则(权值越小的节点离根节点越远)构造最佳归并树。

​  有关最佳归并树的详细介绍见PPT。

归纳:

​  (1) 生成多个初始归并段采用常规方法,产生长度相同的归并段 → 宜采用多路平衡归并(归并中用败者树)

​  (2) 生成多个初始归并段采用置换-选择算法,产生长度不相同的归并段 → 宜采用最佳归并树方案(归并中用败者树)


Comments

Content