(本章设计内容后续会具体讲解)
外排序是指数据存放在外存中,数据排序时涉及内、外存数据交换的排序方法。
存储在外存上的数据以文件为基本单位,由文件系统进行读写操作,读写操作的基本单位为物理块
一、生成若干初始归并段(顺串):这一过程也称为文件预处理。一种常规的方法如下:
产生m=[n/w]个初始归并段。
此时产生的若干子文件称为顺串
二、多路归并:
(所谓多路归并,具体使用几路归并是看计算机内存大小的,如计算机内存为2则只能使用2路归并)
对这些初始归并段进行多遍归并,使得有序的归并段逐渐扩大,最后在外存上形成整个文件的单一归并段,也就完成了这个文件的外排序。
因为该数字打上了队列编号,所以方便我们通知对应的编号队列继续出数字进入中转站队列(保证从中转站中取出的数据是所有文件中最小的),可以看出中转站一直保存了M个记录,当中转站中的所有数字都出队完毕,则本次归并结束。
因为每个小文件都是有序的顺串,所以当内存取出所有小文件第一个数据处理后,将从输出的那个数据所属小文件中再次拿出一个数据,保证了内存中的数据都是各个小文件中最小的那一个
多次使用归并算法,直到所有小文件都被处理完(以二路归并为例):
u个记录需要进行u-1次操作(对各个顺串中数据进行比较)(不考虑∞ (文件中数据读取完再取的话设为∞))
k路归并每次操作需要k-1次关键字比较
总的关键字比较次数为:(u-1)(k-1)
影响归并过程性能因素:
记录读写次数。
内存中归并时需要关键字比较次数。
外排序方法与各种外存设备的特征有关。
影响内排序的数据位置交换,在外排序中变成了记录读写次数,所以此时影响外排序方法性能的主要原因为外存存取数据所花费的时间,即外排序方法与各种外存设备的特征有关
外存设备大体上可以分为两类
1.顺序存取设备(磁带)
2.直接存取设备(磁盘)
文件存储在外存上,因此外排序方法与各种外存设备的特征有关
外存设备大体上可以分为两类
磁带是一种典型顺序存取设备,通过读写头读写数据,对于检索和修改操作十分不便,主要用于处理很少需要修改的并且进行顺序存区的信息,特别用作备份数据的设备
磁带按用途可大致分成录音带、录像带、计算机带和仪表磁带四种。
磁盘是一种直接存取的外存设备,磁盘不仅能够进行顺序存取,而且能直接存取任何记录,他的存取速度比磁盘快得多
磁盘分为硬盘和软盘两种,硬盘的容量比软盘大得多,而且存取速度也比软盘快得多
硬盘结构包括:盘片
、磁头
、盘片主轴
、控制电机
、磁头控制器
、数据转换器
、接口
、缓存
等几个部份。
整个磁盘由多个盘面
组成,固定在同一轴上,沿一个固定方向高速旋转,每个盘面包括上、下两个盘面
,每个盘面用于存储信息,每个盘面有一个读写头
,所有读写头都是固定在一起,同时同步移动的再一个盘面上读写头的轨迹,称为磁道
,磁道就是磁面上的圆环,各个磁面上半径相同的词到总合成为一个柱面
,每个磁道都别切分成很多扇形区域称为扇区
磁盘的容量:磁头数 × 磁道(柱面)数 × 每道扇区数 × 每扇区字节数。
磁头(head)数:每个盘片一般有上下两面,分别对应1个磁头,共2个磁头
磁道(track)数:磁道是从盘片外圈往内圈编号0磁道,1磁道…,靠近主轴的同心圆用于停靠磁头,不存储数据
柱面(cylinder)数:所有盘面上同半径的磁道数量
扇区(sector)数:每个磁道都别切分成很多扇形区域,每道的扇区数量相同
圆盘(platter)数:就是盘片的数量
扇区(sector):
硬件(磁盘)上的最小的操作单位,是操作系统和块设备(硬件、磁盘)之间传送数据的单位。
物理块( block)
block由一个或多个sector组成,是软件(OS、文件系统)
中最小的操作单位;
块是上层软件中(操作文件时)使用的最小的操作单元,就是(操作文件时)一个块一个块进行操作(块的大小格式化时可以设置【如linux、fatfs等等】)
OS的虚拟文件系统从硬件设备上读取一个block,实际为从硬件设备读取一个或多个sector。
物理块是数据在磁盘上的存取单位,也就是每进行一次I/O操作,最小传输的数据大小。
逻辑块
具体文件系统管理的是一个逻辑空间,这个逻辑空间就象一个大的数组,数组的每个元素就是文件系统操作的基本单位逻辑块
逻辑块是从0开始编号的,而且,逻辑块是连续的,与物理块相对应
每个扇区可存储128×2的N次方(N=0.1.2.3)字节的数据(一般为512B),扇区为数据存储的最小单元,外圈的扇区面积比内圈大,为何存储的数据量相同,这是因为内外圈使用的磁物质密度不同,但现在的硬盘已经采用内外圈同密度物质来存储数据了,以减少类似“大面积小数据”的浪费情况。
CHS模式:
有了扇区(sector),有了柱面(cylinder),有了磁头(head),显然可以定位数据了,这就是数据定位(寻址)方式之一,CHS(也称3D),对早期的磁盘(上图所示)非常有效,知道用哪个磁头,读取哪个柱面上的第几扇区就OK了。
CHS模式支持的硬盘容量有限,用8bit来存储磁头地址,用10bit来存储柱面地址,用6bit来存储扇区地址,而一个扇区共有512Byte,这样使用CHS寻址一块硬盘最大容量为256 * 1024 * 63 * 512B = 8064 MB(1MB = 1048576B)(若按1MB=1000000B来算就是8.4GB)
LBA编址方式:
但现在很多硬盘采用同密度盘片,意味着内外磁道上的扇区数量不同,扇区数量增加,容量增加,3D很难定位寻址
新的寻址模式:LBA(Logical Block Addressing)。在LBA地址中,地址不再表示实际硬盘的实际物理地址(柱面、磁头和扇区)。
LBA编址方式将CHS这种三维寻址方式转变为一维的线性寻址,它把硬盘所有的物理扇区的C/H/S编号通过一定的规则转变为一线性的编号,系统效率得到大大提高,避免了烦琐的磁头/柱面/扇区的寻址方式。
在访问硬盘时,由硬盘控制器再将这种逻辑地址转换为实际硬盘的物理地址。LBA下的编号,扇区编号是从0开始。
逻辑扇区号LBA的公式:
LBA(逻辑扇区号)=磁头数 × 每磁道扇区数 × 当前所在柱面号 + 每磁道扇区数 × 当前所在磁头号 + 当前所在扇区号 – 1。
磁盘是直接存取设备,读取一个数据块的时间与当前读写头所处位置关系不大,所以可以通过读写数据块的次数来衡量存取时间
对存放在磁盘中的文件进行排序属于典型的外排序,称为磁盘排序(disk sort),其磁盘排序过程与外排序所用归并排序过程基本相同
磁盘中的Fin文件存储着待排序的数据,通过计算讲Fin文件中的记录一部分一部分的调入内存处理,产生若干个文件F1…Fm,他们经过处理后都是有序的,称为顺串
,然后再次将F1…Fm依次调入内存,通过相关归并算法生成Fout文件
实际上文件系统在读取时每次读取一个物理块,而一个物理块中可能有多个记录(数据),但为了方便起见以下每个记录占用一个物理块(读写记录只需要进行一次读写操作)
按照内存大小将初始文件分为若干份( 我们假设需要排序的int数有12个,内存一次只能装下3个int数,就把12个数据分成4份(12/3=4),然后通过内排序处理成有序子串)
置换-选择排序方法生成初始归并段,该方法可以减少生成的初始归并段个数(初始归并段个数越少,则越接近最后排序结果,可以减少归并次数)
总结:
共有n个记录,内存工作区WA的容量为w:
若在w个记录中选取最小关键字的采用简单比较方法,每次需要w-1次比较。
使用败者树可以提高比较效率
读出和写入均为n
什么是k路平衡归并:
根据内存大小可以划分为不同的多路归并方案
2路平衡归并:每一趟从m个归并段得到[m/2]个归并段。
处理时把两个小的有序子串合并成一个大的有序子串(二路归并)
多次使用归并算法,直到所有小文件都被处理完
总结:
每归并一次,参与归并的每个记录都要读一次和写一次。
总的读记录数(写记录数与之相同):
总的读记录数等同于哈夫曼树WPL(带权路径长度):
影响k路平衡归并的因素
败者树
败者树是一棵有k个叶子节点的完全二叉树(可以将大根堆看成胜者树,小根堆看成败者树),其中叶子节点存储参与归并的记录,分支节点存放关键字对应的段号。
所谓败者
是两个记录比较时关键字较大者,胜者是两个记录比较时关键字较小者
败者树用于在k个记录中选取最小关键字的记录。败者树类似于堆排序中的小根堆。
利用败者数实现k路平衡归并的过程,是先建立败者树,然后对k个输入有序段进行k路平衡归并
一、先建立败者树
建立败者数是采用类似于小根堆调整的方法实现的,初始时令所有的分支结点指向一个含最小关键字的叶子节点,然后从叶子结点出发,调整分支节点为新的败者(比较时关键字较大者)即可
例子,k=5:
首先构造非叶子节点n2=n0-1=k-1=4
每个叶子结点对应一个归并段,段号为0~4。
初始时每个分支结点取值“5(-∞)”,5表示段号(此时为虚拟段号,实际段号为0~4),- ∞表示最小关键字。
例如,某结点取值为“4(15)”,表示结点值来自4号段的关键字15对应的记录。
调整产生冠军(最小者)的过程
从F4=>F0重复操作:将当前结点的关键字与父结点比较,将大的(败者)放在父结点中,小者(胜者)继续进行,直到根结点。最后将胜者放在冠军结点中。
二、用败者树进行归并
取每个输入有序段的第一个记录,作为败者树的叶子节点,建立初始败者数
两两叶子节点进行比较,在双亲节点中存放比较的败者(关键字较大者),而让胜者去参加更高一层的比赛,如此在根节点之上胜出的冠军是所有关键字最小者
将胜出的记录(冠军)写至输出归并段,在对应的叶子节点处补充其输入有序段的下一个记录,若该有序段变空,则补充一个大关键字(比所有关键字都大,设为∞)的虚记录 ∞
调整败者树,选择新的冠军(最小的记录)
从补充记录的叶子节点向上和双亲结点的关键字比较败者留在该双亲节点,胜者继续向上,直到树的根结点,最后将胜者放在根节点的双亲节点中 作为冠军
若胜出的记录关键字等于∞则归并结束,否则重复(2)
例子,归并过程:
取出的冠军为1(5),从1号段中取下一个记录,沿着个分支向上操作,产生次小的记录。重复操作直到冠军为∞
总结
关键字比较次数与k无关 , 总的内部归并时间不会随k的增大而增大。
只要内存空间允许,尽可能增大归并路数k。
采用败者树,置换-选择排序中关键字比较次数分析
共有n个记录,内存工作区WA的容量为w:若在w个记录中选取最小关键字的采用败者树方法,每次需要log2w次比较。总的时间复杂度为O(nlog2w)。
使用常规方法生成的初始归并段记录数是相同的,使用置换-选择排序方法生成的顺串可能会导致顺串与顺串中记录个数不同
k路平衡归并适合初始归并段中的记录个数相同的情况,当初始归并段中的记录个数不同时哪些初始归并段先归并,哪些后归并都会影响算法的性能
若记录数多的先归并记录数少的归并段后归并,会导致该归并段参与的归并次数比记录少的归并段归并次数多,而读写次数计算和哈夫曼树WPL相同,从根结点到各个叶结点的路径长度与相应结点权值的乘积的和,可知算法效率显然不高
(假设k=3)
解决的方法是加虚段(长度为0的段),每次恰好k个段进行归并
应加(k-1)-(m-1) Mod(%) (k-1)个虚段
构建最佳归并树(m个初始归并段)就是构建带权路径长度最短的k叉(阶)哈夫曼树
一、计算是否需要增加虚短
若x=(m-1) Mod (k-1)≠0,则需附加(k-1)-x个虚段,以使每次归并都可以对应k个段。
二、按照哈夫曼树的构造原则(权值越小的结点离根结点越远)构造最佳归并树。
(1)给定的n个权值[例:W1.W2.。。](这里的权值是归并段中的记录个数)构造n棵只有一个叶结点的叉树,从而得到一个二叉树的集合F-{T1… Ti.cum.}
(2)将二叉树集合F排序
(3)在F中选取四个长度最小的归并段,将作为叶子节点,其值累加和为其父节点值
(4)在森林F中再次选取3个归并段与叶子节点的父节点累加构造出一个父节点
(5)重复4直到只剩下F一棵树为止,这棵树就是最佳归并树
总结:
两者之间的区别不过是归并方案不同
由此选择归并方法时
磁带:属顺序存取设备。
磁带排序主要解决多个磁带交替使用的问题。
磁带排序也是外排序的一种,也使用多路归并排序
磁带多路平衡归并排序过程与磁盘的多路平衡归并排序过程基本上相同。
磁带排序和磁盘排序的主要不同之处在于磁带排序需要充分考虑归并段的分布状况。
磁带是顺序存取的,所以各归并段分布在不同磁带和同一磁带的不同位置对排序效率影响极大。
多阶段归并排序 属于多路非平衡归并排序,即各条带上的归并段不再保持平衡分布。
使用磁带多阶段归并排序 是因为在进行磁带多路平衡归并排序时,重新分布有序段的问题需要使用的磁带数量是比较多的(k路归并时,需要使用2k个磁带,k个磁带做输入带,k个磁带做输出带)
在k路多阶段归并中仅使用k+1条磁带,就可避免在多路平衡归并排序法中遇到的重新分布有序段的问题。
多阶段归并排序过程:
开始时,初始归并段不平衡地分配在前k条磁带上(输入带),第k+1条磁带作为输出带,开始为空。
假设有17个初始归并段为(S1,S2,…,S17),用4台磁带机Tl、T2、T3和T4做三路的多阶段归并排序,其初始归并段的分布情况及排序过程中各磁带数据的变化情况。
为了使归并的趟数达到最少,必须合理地分配各磁带上初始归并段的段数,归并段的总数以及在各带上的分布情况与k阶广义Fibonacci(斐波那契)序列有对应关系。
初始归并段在各带上分布的段数应为:
k阶Fibonacci数列可用下面的递推公式导出: