大文件排序问题

题目:有一个大文件,里面记录了若干数字,把这些数字进行排序。文件大小远大于内存大小。
思路:内存极少的情况下,利用分治策略,利用外存保存中间结果,再用多路归并来排序

(1)按可用内存的大小,把外存上含有n个记录的文件分成若干个长度为L的子文件,把这些子文件依次读入内存,并利用有效的内部排序方法对它们进行排序,再将排序后得到的有序子文件重新写入外存;

(2)对这些有序子文件逐趟归并,使其逐渐由小到大,直至得到整个有序文件为止。

若干小文件排序

题目:有N(N远大于10)个1MB的小文件,文件里记录了若干数字,现要求在2M内存里对这些小文件中的数字排序。
思路:多路归并排序

1. 首先对每个小文件中的数字排序,2M内存足够对1M数字排序。

2. 现在有了N个有序的小文件,怎么合并成1个有序的大文件?

利用如下原理进行归并排序:
大文件排序问题_第1张图片

举例说明:
文件1:3,6,9
文件2:2,4,8
文件3:1,5,7

第一回合:
文件1的最小值:3 , 排在文件1的第1行
文件2的最小值:2,排在文件2的第1行
文件3的最小值:1,排在文件3的第1行
那么,这3个文件中的最小值是:min(1,2,3) = 1
也就是说,最终大文件的当前最小值,是文件1、2、3的当前最小值的最小值,绕么?
上面拿出了最小值1,写入大文件.

第二回合:
文件1的最小值:3 , 排在文件1的第1行
文件2的最小值:2,排在文件2的第1行
文件3的最小值:5,排在文件3的第2行
那么,这3个文件中的最小值是:min(5,2,3) = 2
将2写入大文件。

也就是说,最小值属于哪个文件,那么就从哪个文件当中取下一行数据。
(因为小文件内部有序,下一行数据代表了它当前的最小值)

3. 如何在N个数中找到最小值呢?

经典的算法的步骤是:
每次从k个组中的首元素中选一个最小的数,加入到新组,这样每次都要比较k-1次,故算法复杂度为O((n-1)*(k-1));

而如果使用胜者树,可以在O(logk)的复杂度下得到最小的数,算法复杂度将为O((n-1)*logk), 对于外部排序这种数据量超大的排序来说,这是一个不小的提高。

胜者树和败者树都是完全二叉树,是树形选择排序的一种变型。
每个叶子结点相当于一个选手,每个中间结点相当于一场比赛,每一层相当于一轮比赛

不同的是,胜者树的中间结点记录的是胜者的标号;而败者树的中间结点记录的败者的标号。

胜者树与败者树可以在log(n)的时间内找到最值

任何一个叶子结点的值改变后,利用中间结点的信息,还是能够快速地找到最值。在k路归并排序中经常用到。

下图是一个胜者树的示例。规定数值小者胜。
1. b3 PK b4,b3胜b4负,内部结点ls[4]的值为3;
2. b3 PK b0,b3胜b0负,内部结点ls[2]的值为3;
3. b1 PK b2,b1胜b2负,内部结点ls[3]的值为1;
4. b3 PK b1,b3胜b1负,内部结点ls[1]的值为3。
大文件排序问题_第2张图片

因此,上述问题的解决思路如下:
1. 对每个小文件排序。
2. 读取每个文件的首元素,用胜者树找到最小值,记录到大文件上。
3. 继续采用多路归并排序的方法,继续找最值,直到排完所有的文件。

此方法也适用于大文件排序,先将大文件分割成若干可以装入内存的小文件,用以上方法进行排序。

你可能感兴趣的:(算法数据结构,剑指offer)