赞
踩
有时,待排序的文件很大,计算机内存不能容纳整个文件,这时候对文件就不能单纯的使用内部排序了,还得采取一些其他的策略。因此需要将待排序的记录存储到外存上,排序时再将数据一部分一部分地调用内存进行排序,在排序过程中需要多次进行内存和外存之间地交换,这种排序方法就成为外部排序。
文件通常是按块存储在磁盘上的,操作系统也是按块对磁盘上的信息进行读写的。因为磁盘读/写的机械动作所需的时间远远超过内存运算的时间,因此外部排序过程中的时间代价主要考虑访问磁盘的次数,即I/O次数。
外部排序常采用的排序方法是归并排序,这种归并方法由两个不同的阶段组成:
(1)初始状态
(2)将
(
36
,
8
,
26
)
(36,8,26)
(36,8,26)和
(
42
,
9
,
48
)
(42,9,48)
(42,9,48)分别存入输入缓冲区
1
1
1和输入缓冲区
2
2
2
(3)将输入缓冲区
1
1
1和输入缓冲区
2
2
2的数据进行递增排序
(4)将输入缓冲区
1
1
1和输入缓冲区
2
2
2的数据通过输出缓冲区逐一写入外存,形成一个有序归并段
(5)对于
(
1
,
37
,
25
)
(1,37,25)
(1,37,25)和
(
45
,
27
,
28
)
(45,27,28)
(45,27,28)进行上述同样的操作后得到的结果:
(6) 对剩余
12
12
12块内存依次进行上述操作,总共需要进行
16
16
16次读操作和
16
16
16次写操作,得到初始归并段。
(7)第一次归并:读入归并段
1
1
1和归并段
2
2
2中的第一块磁盘(相对最小),进行排序:
(8)依次找出这两个输入缓冲区中最小元素,并将其移动到输出缓冲区中,当输出缓冲区满,则写入外存
(
1
,
8
,
9
)
(1,8,9)
(1,8,9)
(9)继续找出这剩余元素中的最小元素,直到某一个缓冲区中空,则读入其所属归并段的后一个内存块的数据,并继续进行上述操作。直到两个缓冲区都空,且归并段 1 1 1和归并段 2 2 2中的元素全部读入内存,此时归并段 1 1 1和归并段 2 2 2就得到了一个有序的递增序列。
当输入缓冲区空了时:
输入归并段
1
1
1的第二块内存
排序完成,归并段
1
1
1和归并段
2
2
2递增有序
(10)对剩余的六个归并段进行上述操作,八个归并段→四个归并段
(11)第二次归并:继续采用此方法依次取出归并段
1
1
1和归并段
2
2
2(归并段
1
1
1为八个归并段时的归并段
1
1
1和归并段
2
2
2,归并段
2
2
2为八个归并段时的归并段
3
3
3和归并段
4
4
4)的各个块进行排序操作:四个归并段→两个归并段。
(12)第三次归并:继续排序归并段
1
、
2
1、2
1、2,形成最后的有序递增序列
总时间开销 = 内部排序所需时间 + 内部归并所需时间 + 外部读写所需时间
若改用 4 4 4路归并排序,则只需 2 2 2趟归并,外部排序时的总读/写次数便减至 32 × 2 + 32 = 96 32×2+ 32= 96 32×2+32=96。因此,增大归并路数,可减少归并趟数,进而减少总的磁盘 I / O I/O I/O次数。
一般地,对 r r r个初始归并段,做 k k k路平衡归并,归并树可用严格 k k k叉树(即只有度为 k k k与度为 0 0 0的结点的 k k k叉树)来表示。第一趟可将 r r r个初始归并段归并为 ⌈ r / k ⌉ ⌈r/k⌉ ⌈r/k⌉个归并段,以后每趟归并将 m m m个归并段归并成 ⌈ m / k ⌉ ⌈m/k⌉ ⌈m/k⌉个归并段,直至最后形成一个大的归并段为止。 树的高度 − 1 = ⌈ l o g k r ⌉ = 归并趟数 S 树的高度-1=⌈log_kr⌉=归并趟数S 树的高度−1=⌈logkr⌉=归并趟数S。可见,只要增大归并路数 k k k,或减少初始归并段个数 r r r,都能减少归并趟数 S S S,进而减少读写磁盘的次数,达到提高外部排序速度的目的。
为了使内部归并不受 k k k的增大的影响,引入了败者树。败者树是属性选择排序的一种变体,可视为一棵完全二叉树。
将每个归并段的第一个元素作为叶子结点加入败者树中
从左至右、从上往下的更新分支节点的信息:判断其左右子树的大小,除了根节点(最上面那个结点)记录冠军来自哪个归并段外,其余各分支节点记录的是失败者来自哪个归并段。
取出最小的元素
1
1
1后,从其所属的归并段中取出下一个元素
6
6
6,依次与从叶子结点到根节点的各个结点所记录的败者信息进行对比。
引进败者树后,选出最小的关键字,仅需
l
o
g
2
k
log_2k
log2k次比较(向上取整)。
可见,使用败者树后,内部归并的比较次数与 k k k无关了。因此,只要内存空间允许,增大归并路数 k k k将有效地减少归并树的高度,从而减少 I O IO IO次数,提高外部排序的速度。
值得说明的是,归并路数k并不是越大越好。归并路数 k k k增大时,相应地需要增加输入缓冲区的个数。若可供使用的内存空间不变,势必要减少每个输入缓冲区的容量,使得内存、外存交换数据的次数增大。当 k k k值过大时,虽然归并趟数会减少,但读写外存的次数仍会增加。
使用选择置换排序,可以让每个初始段的长度不再受限于内存工作区大小,设内存工作区最多容纳 w w w个数据:
(1)初始状态
(2)将
(
4
,
6
,
9
)
(4,6,9)
(4,6,9)放入到内存工作区中,此时输出
4
4
4并修改
M
I
N
=
4
MIN=4
MIN=4
(3)加入
7
7
7,选择最小元素
6
6
6,输出
6
6
6并修改
M
I
N
=
6
MIN=6
MIN=6
(4)重复上述步骤,当放入
10
10
10时,此时
M
I
N
=
13
MIN=13
MIN=13,
10
10
10不能输出
选择第二小的元素
14
14
14输出,并修改
M
I
N
=
14
MIN=14
MIN=14
(5)继续上面的步骤,当输出
30
30
30后,此时
M
I
N
=
30
MIN=30
MIN=30,将下一个文件块放入到内存工作区中,此时内存工作区的所有元素都小于
M
I
N
MIN
MIN,因此第一个归并区到上一个输出元素为止
(
4
、
6
、
7
、
9
、
11
、
13
、
14
、
16
、
22
、
30
)
(4、6、7、9、11、13、14、16、22、30)
(4、6、7、9、11、13、14、16、22、30)
(6)继续上述步骤,将新来的元素放到归并段
2
2
2中,此时内存工作区中最小的元素为
2
2
2,输出
2
2
2并将
M
I
N
MIN
MIN修改为
2
2
2。当输出到
36
36
36时,内存工作区中的所有元素都小于
M
I
N
MIN
MIN,因此第二个归并区到上一个输出元素为止
(
2
、
3
、
10
、
17
、
19
、
20
、
23
、
36
)
(2、3、10、17、19、20、23、36)
(2、3、10、17、19、20、23、36)
(7)继续上述步骤,将新来的元素放到归并段
3
3
3中,此时内存工作区中最小的元素为
1
1
1,输出
1
1
1并将
M
I
N
MIN
MIN修改为
1
1
1。直到所有元素都输出完毕之后,第三个归并区为
(
1
、
5
、
12
、
18
、
21
、
39
)
(1、5、12、18、21、39)
(1、5、12、18、21、39)
https://blog.csdn.net/JiangNan_1002/article/details/124306250
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。