外排序

外排序

方法介绍

所谓外排序,顾名思义,便是在内存外面的排序,由于当要处理的数据量很大,而不能一次装入内存时,此时只能放在读写较慢的外存储器(一般是硬盘)上。算法

外排序一般采用的是一种“排序-归并”的策略。编程

  • 在排序阶段,先读入能放在内存中的数据量,将其排序输出到一个临时文件,依此进行,将待排序数据组织为多个有序的临时文件;
  • 尔后在归并阶段将这些临时文件组合为一个大的有序文件,也即排序结果。

假定如今有20个数据的文件A:{5 11 0 18 4 14 9 7 6 8 12 17 16 13 19 10 2 1 3 15},但一次只能使用仅装4个数据的内容,因此,咱们能够每趟对4个数据进行排序,即5路归并,具体方法以下述步骤:数组

  • 咱们先把“大”文件A,分割为a1,a2,a3,a4,a5等5个小文件,每一个小文件4个数据spa

    • a1文件为:5 11 0 18
    • a2文件为:4 14 9 7
    • a3文件为:6 8 12 17
    • a4文件为:16 13 19 10
    • a5文件为:2 1 3 15
  • 而后依次对5个小文件分别进行排序code

    • a1文件完成排序后:0 5 11 18
    • a2文件完成排序后:4 7 9 14
    • a3文件完成排序后:6 8 12 17
    • a4文件完成排序后:10 13 16 19
    • a5文件完成排序后:1 2 3 15
  • 最终多路归并,完成整个排序排序

    • 整个大文件A文件完成排序后:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

问题实例

一、给10^7个数据量的磁盘文件排序内存

输入:给定一个文件,里面最多含有n个不重复的正整数(也就是说可能含有少于n个不重复正整数),且其中每一个数都小于等于n,n=10^7。 输出:获得按从小到大升序排列的包含全部输入的整数的列表。 条件:最多有大约1MB的内存空间可用,但磁盘空间足够。且要求运行时间在5分钟如下,10秒为最佳结果。字符串

解法一 :位图方案input

你可能会想到把磁盘文件进行归并排序,但题目要求你只有1MB的内存空间可用,因此,归并排序这个方法不行。it

熟悉位图的朋友可能会想到用位图来表示这个文件集合。例如正如编程珠玑一书上所述,用一个20位长的字符串来表示一个全部元素都小于20的简单的非负整数集合,边框用以下字符串来表示集合{1,2,3,5,8,13}:

0 1 1 1 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0

上述集合中各数对应的位置则置1,没有对应的数的位置则置0。

参考编程珠玑一书上的位图方案,针对咱们的10^7个数据量的磁盘文件排序问题,咱们能够这么考虑,因为每一个7位十进制整数表示一个小于1000万的整数。咱们可使用一个具备1000万个位的字符串来表示这个文件,其中,当且仅当整数i在文件中存在时,第i位为1。采起这个位图的方案是由于咱们面对的这个问题的特殊性:

  1. 输入数据限制在相对较小的范围内,
  2. 数据没有重复,
  3. 其中的每条记录都是单一的整数,没有任何其它与之关联的数据。

因此,此问题用位图的方案分为如下三步进行解决:

  • 第一步,将全部的位都置为0,从而将集合初始化为空。
  • 第二步,经过读入文件中的每一个整数来创建集合,将每一个对应的位都置为1。
  • 第三步,检验每一位,若是该位为1,就输出对应的整数。

通过以上三步后,产生有序的输出文件。令n为位图向量中的位数(本例中为1000 0000),程序能够用伪代码表示以下:

//磁盘文件排序位图方案的伪代码  
//copyright@ Jon Bentley  
//July、updated,2011.05.29。  

//第一步,将全部的位都初始化为0  
for i ={0,....n}      
   bit[i]=0;  
//第二步,经过读入文件中的每一个整数来创建集合,将每一个对应的位都置为1。  
for each i in the input file     
   bit[i]=1;  

//第三步,检验每一位,若是该位为1,就输出对应的整数。  
for i={0...n}      
  if bit[i]==1        
    write i on the output file

上述的位图方案,共须要扫描输入数据两次,具体执行步骤以下:

第一次,只处理1—4999999之间的数据,这些数都是小于5000000的,对这些数进行位图排序,只须要约5000000/8=625000Byte,也就是0.625M,排序后输出。 第二次,扫描输入文件时,只处理4999999-10000000的数据项,也只须要0.625M(可使用第一次处理申请的内存)。 所以,总共也只须要0.625M 位图的的方法有必要强调一下,就是位图的适用范围为针对不重复的数据进行排序,若数据有重复,位图方案就不适用了。

不过很快,咱们就将意识到,用此位图方法,严格说来仍是不太行,空间消耗10^7/8仍是大于1M(1M=1024*1024空间,小于10^7/8)。

既然若是用位图方案的话,咱们须要约1.25MB(若每条记录是8位的正整数的话,则10000000/(1024 1024 8) ~= 1.2M)的空间,而如今只有1MB的可用存储空间,那么究竟该做何处理呢?

解法二 :多路归并

诚然,在面对本题时,还能够经过计算分析出能够用如2的位图法解决,但实际上,不少的时候,咱们都面临着这样一个问题,文件太大,没法一次性放入内存中计算处理,那这个时候咋办呢?分而治之,大而化小,也就是把整个大文件分为若干大小的几块,而后分别对每一块进行排序,最后完成整个过程的排序。k趟算法能够在kn的时间开销内和n/k的空间开销内完成对最多n个小于n的无重复正整数的排序。

好比可分为2块(k=2,1趟反正占用的内存只有1.25/2M),1~4999999,和5000000~9999999。先遍历一趟,首先排序处理1~4999999之间的整数(用5000000/8=625000个字的存储空间来排序0~4999999之间的整数),而后再第二趟,对5000001~1000000之间的整数进行排序处理。

解法总结

一、关于本章中位图和多路归并两种方案的时间复杂度及空间复杂度的比较,以下:

时间复杂度        空间复杂度

位图          O(N)          0.625M

多位归并   O(Nlogn)             1M

(多路归并,时间复杂度为O(k n/k logn/k ),严格来讲,还要加上读写磁盘的时间,而此算法绝大部分时间也是浪费在这上面)

二、bit-map

适用范围:可进行数据的快速查找,判重,删除,通常来讲数据范围是int的10倍如下

基本原理及要点:使用bit数组来表示某些元素是否存在,好比8位电话号码

扩展:bloom filter能够看作是对bit-map的扩展

触类旁通

、已知某个文件内包含一些电话号码,每一个号码为8位数字,统计不一样号码的个数。 8位最多99 999 999,大概须要99m个bit,大概10几m字节的内存便可。

相关文章
相关标签/搜索