外部排序算法

1. 桶排序(bucket sort)

  1. 概述

当待排序的数据范围变化很小时,假设最小值为min,最大值为max,那么我们可以创建max-min+1个Bucket用于统计每个数出现的次数。排序的时候只需要每次执行读文件的操作,并将读到的数据对应桶的技术加1即可。在输出的时候,按照min到max的顺序依次将桶中的数据(如果数据出现多次,也需要写入多次)写入输出文件即可。

  1. 适用场景

待排序数据分布在一个小的范围内,如高考几百万个考生考试分数的排序


2. 位图(bit-map)

  1. 概述

位图是一种通过使用每一位(bit)表示一个数,从而减少内存使用量的方法。BitMap中的某一位为1表示其对应的数存在,为0表示其对应的数不存在。排序的时候,我们先创建BitMap(BitMap可以自己实现),然后依次从文件中读入数值,将BitMap对应位设置为1。在输出时,我们从BitMap的低位到最高位,依次判断当前位是否为1,如果为1,那么就将对应的数值写入输出文件。

  1. 适用场景

待排序数据不存在重复,如对几千万个电话号码进行排序、找出几亿个整数中不重复的整数的个数(使用两个bits表示一个数,0表示没有出现、1表示出现一次、2表示出现多次)


3. 多路归并(merge sort)

  1. 概述

多路归并的基本思路和归并排序一样,其实归并排序就是2路归并。我们使用内部排序算法(快速排序等)对划分的K个部分(保证每个部分的数据都能装载到内存中)分别进行排序,并将排序后的结果存储到k个临时文件中,在最后使用简单选择或者败者树的方式进行归并,将数值写入输出文件。

  1. K增大对性能的影响

假设待排序的数据需要划分为8段,才能使得每一段都能够全部装载到内存中,以2路归并排序和8路归并排序为例,讨论K增大对性能的影响。

  • 首先8路归并很好分析,对所有数据只需要2次读操作和2次写操作。第一次读操作为将数据从原始文件中读入内存进行内部排序,第一次写操作为将部分排序的数据写入临时文件。第二次读操作为将部分排序的数据读入内存进行归并,并在每一次选择到当前最小值时将其写入输出文件。
  • 而对于2路归并而言,对所有数据需要4次读操作和4次写操作,分析过程和8路归并排序类似,不再赘述。
  • 规律:对于K路归并排序而言,所有数据需要执行的读操作和写操作的次数为lgk(n) + 1,其中n为总段数,k为每次归并的段数。也就是说K越大,文件读写操作越少,归并算法性能越好。
  1. 简单选择和败者树的比较
  • 简单选择是从K个数中通过比较的方式选择出最小的一个,然后写入输出文件,每次选择的时间复杂度为O(k),显然随着K的增大,此过程的时间开销会线性增长。
  • 败者树也是从K个数中选择出最小的一个,然后写入输出文件,不同的是每次选择的时间复杂度为O(lgK)。
  • 结论:使用败者树能够优化归并过程
  1. 适用场景

所有需要进行外部排序的场景


Java实现

猜你喜欢

转载自blog.csdn.net/a16302010048/article/details/103845669