阿里的一道笔试题,一开始没有想法,同学提示才了解的这个算法。
题目: 有10个文件,每个文件有1000万行,文件内容的每一行为一个正整形数字;需要,写一个程序,将所有数字排序,分为10个文件输出,如0号文件包含前1000万个数字,1号文件文件包含1千万-2千万之间的数字,依次类推。
限制:如果使用java,-Xmx需要设置为32MB;其它语言也需限制内存为32MB。
题目分析
题目模拟了一种情况,即是说当数据量远大于内存存储空间时,应当如何排序。这种情况下显然无法将数据装入内存进行排序,需要利用硬盘空间对文件进行排序,这种算法称为外部排序算法。
外部排序算法通过将排序中间过程保存在硬盘上,降低内存的占用,从这个角度讲,这是一种以时间换取空间的排序方式。
外部排序算法采用多路归并的方式,首先将大文件分解为较为适合文件系统大小的有序文件,再按照合并的路数对文件的顺序进行合并。得到最终的结果。
在算法书中提到,多路归并算法使用胜者树,或者败者树实现。因为在路数已经确定的情况下,胜者树和败者树不需要花费过多的代价去维护数据。在实际实现过程中,可以直接使用优先队列进行维护。
在这里,就得到了算法的完整思路。
- 分次读入数据,并将读入的数据排序,然后保存在硬盘上。设分为了
R1, R2, R3 ... Rn
个文件。 - 每次按路数将文件进行分组,分为
{R1, R2, ... Rk}
,{Rk, Rk+1, ... R2k}
。。。{Rmk, Rmk+1, ... Rn}
组,其中k为路数。 - 将以上文件进行合并,合并的方法为,每次从每个文件中读出一个数,并入堆或胜者树或败者树,然后再从中选取最小值输出。
- 重复以上步骤,就可以逐次将文件有序化。
- 由于IO的效率较低,在排序过程中,可以考虑使用多线程方式提高时间的利用效率。