数据结构---排序算法总结(外部排序)

1. 很久以前没有胭脂,女子的脸只为情郎红。

2. 世界如此广阔,你却走进了悲伤的墙角

1. 排序:

2. 插入排序

2.1. 直接插入排序

2.2. 折半插入排序

2.3. 希尔排序

3. 交换排序

3.1. 冒泡排序

3.2. 快速排序

4. 选择排序

4.1 简单选择排序

4.2 堆排序

5. 归并排序和基数排序

6. 各种内部排序算法的比较及其应用

7. 外部排序

要点

  • 外部排序指待排文件较大,内存一次放不下,需存放在外部介质的文件的排序
  • 为减少平衡归并中外存读写次数所采取的方法:增大归并路数 减少归并段个数
  • 利用败者树增大归并路数
  • 利用置换-选择排序增大归并段长度来减少归并段个数
  • 由长度不等的归并段,进行多路平衡归并,需要构造最佳归并树

基本概念:

前面的排序都是在内存中进行的(称之为内部排序)。然而实际应用中,经常需要对大文件进行排序,因为文件中记录很多,信息量庞大,所以无法将整个文件拷贝进内存中进行排序

因此,需要将待排序的记录存储在外存上,排序时再把数据一部分一部分的调入内存中进行排序。在排序的过程中,需要多次进行内存和外存之间的交换,对外存文件中的记录排序之后仍然存到原文件,这种排序方法称之为外部排序

主要考虑:

主要关心访问磁盘的次数。因为磁盘的读写的机械动作(I/O次数)所需要的时间要远远超过内部排序的时间

外部排序分类:

根据外存设备的不同,可以将排序分之为磁盘文件排序(直接存取设备)和磁带文件排序(顺序存取设备)

外部排序过程:

外排主要采用归并排序方法。分为两个阶段:

第一阶段:1,2,3,由此得到归并段;

第二阶段:4:归并段二路归并得到更大的归并段。

  1. 根据内存缓冲区的代销,将外存上含n个记录的文件分成若干个长度为h的子文件
  2. 一次读入内存并利用有效的内部排序方法(插入排序,交换排序,选择排序,归并和基排序)对它们排序
  3. 将排序后的得到的有序文件重新写回外存,通常称这些有序文件为归并段或者顺串
  4. 然后对这些归并段进行逐趟归并,使归并段(有序的子文件)逐渐由小变大,直到整个文件都有序为止

例子:

一个含有2000个记录的文件,每个磁盘块可以容纳250个记录,则该文件包括8个磁盘块(R1-R8)。然后对该文件做二路归并排序,每次往内存中读取两个磁盘块,排序后再写回磁盘。若把内存工作区分为3个缓存区,其中两个为输入缓存区(缓存区1和缓存区2),一个为输出缓存区,可以在内存中利用内部排序方法(二路归并merge函数)实现二路归并。

具体做法:

1. 从参加归并排序的两个输入归并段R1和R2分别读入一个块(注意用词,这里说的是一个块,没说一定要把所有都写到对应的输入缓冲区中,第一次归并的时候直接将两个归并块放入输入缓存区正好放满,但是之后的第二第三次归并就要再取放在输入缓存区1(每次在输入缓存区中找最小值?下面验证)和输入缓存区2,然后在内存中进行二路归并。归并出来的对象顺序存放在输出缓存区中。

若输入缓存区存满,则将其内的对象顺序写到输出归并段R1'中,再将输出缓存区清空,继续存放归并后的对象。

若某一个输入缓存区中的对象取空,则从对应的输入归并段中再读取下一磁盘块(这种情况在第一趟归并时不会出现),继续参加排序,如此继续归并,直到两个归并段中的对象全部读入内存并都归并完成为止。

2. 当R1和R2归并完之后,再归并R3和R4,R5和R6,R7和R8,这样算一趟归并。

3. 再把上次归并得到的结果R1',R2',R3',R4'两两归并,这是第二次归并。

4. 最后把R1''和R2''两个归并段进行排序,这是第三次归并。

所以一共进行了3趟归并。

外部排序的总时间:

外部排序的总时间 =

内部排序所需要的总时间(二路归并merge) +

外存信息读写的时间(I/O操作) +

内部归并所需要的时间(二路归并)

Note:

由于外存上信息的读/写是以“物理块”为单位的,并且每个物理块可容纳250个记录。可知每一趟归并需要8次“读”和8次“写”,3趟归并加上内部排序的时候还要进行一次I/O(将外存上的对象一个个放进内存再放回去(这算是一个读写过程)),所以总共需要((8+8)*(3+1)) = 64次读写,所以上述二路平衡排序的总时间是:

r * 每一个归并段内部排序的总时间 +  64 * T(I/O) + S(n-1)* 每做一次归并,取得一个关键字最小的记录的时间。

r是归并段数 = 8

S是归并趟数  

n是每趟参加二路归并的记录的个数

但是对于四路归并排序,那么就只需要进行两趟归并,外排时总的读写次数便减小至2 * 16 + 16 = 48次

因此,增大归并路数就可以减少归并趟数,从而减少总的磁盘I/O总数

只要增大归并路数m,或者减少初始归并段个数r,都能减少读写磁盘次数d,进而提高外排速度。

多路归并归并与败者树(使内部排序不受m增大从而产生影响的手段)

注意哈,上面增加了归并路数的时候,可以减少归并段数S,进而减少I/O次数,但是!

当增加归并段的时候,内部排序的时间也会增加,这将抵消增大m而减少I/O次数带来的效益,所以!

不能使用普通的内部归并算法。

为了使内部排序的时间不受增大m的影响,提出了败者树。(树形排序的一种变形,可以看做是完全二叉树)

特点:

叶节点:存放各归并段在归并过程中当前参加比较的记录

内部结点:存放左右子树中的失败者,而让胜利者继续向上比较,一直到根节点

如此比较两个数,大的为失败者,小的为胜利者,则根节点指向的数为最小数

使用败者树之后,内部归并的比较次数就和m没有关系了,因此,只要内存空间允许,增大归并路数就能有效地减少归并树的高度,从而减少I/O操作的次数,提高外部排序的速度。

但是凡事都有一个度,m并不是越大越好,当归并路数增加的时候,就要相应地增加内存中输入缓冲区的个数,如果可以使用的内存空间不变,这样势必会减少输入缓冲区的容量,使得内外存交换数据的次数增大,所以读写外存的次数也会增加。

置换-选择排序

前面提到,不光是增加归并路数,减少初始段的长度也是一个好办法减少外排的时间。

最佳归并树

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(数据结构)