问题描述:
输入:给定一个文件,里面最多含有n个不重复的正整数(也就是说可能含有少于n个不重复正整数),且其中每个数都小于等于n,n=10^7。
输出:得到按从小到大升序排列的包含所有输入的整数的列表。
条件:最多有大约1MB的内存空间可用,但磁盘空间足够。且要求运行时间在5分钟以下,10秒为最佳结果。
分析文件大小:
10^7 = 1000,0000 = 10,000,000
一个数据=1B,那么大约为10M
归并排序(二路归并排序):
你可能会想到把磁盘文件进行归并排序,但题目要求你只有1MB的内存空间可用,所以,归并排序这个方法不行。
最终解决办法:
外排序(快速排序+多路归并排序):
内存中快速排序
- 由于要求的可用内存为1MB,那么每次可以在内存中对250K的数据进行排序,然后将有序的数写入硬盘。
- 那么10M的数据需要循环40次,最终产生40个有序的文件。
个人理解:
1. 按个数 1000 个 ,文件内遍历每个数字做mod/1000操作,把数据分散到1000个文件中。每个小文件大约40KB大小。
2. 1000个小文件,分别导入内存做快排或者任何nlogn排序
3. 内存中创建,
//自定义从小到大排序
std::priority_queue < int, vector<int>, greater<int> > pq_int;
每次分别从1000个文件中读取一个数值(这个数值是每个文件中最小的一个),push到优先级队列内,写入队列后,优先级队列会自动排序,内部机制是堆排序,然后打印队列内1000个数值,即为结果(相当于归并排序)
接着,继续从1000个小文件内继续读取后面的数值,写入优先级队列,排序输出。
4.基本思想就是,拆分大文件,各个击破小文件,归并处理结果。
多路归并排序
- 将每个文件最开始的数读入(由于有序,所以为该文件最小数),存放在一个大小为40的first_data数组中;
- 选择first_data数组中最小的数min_data,及其对应的文件索引index;
- 将first_data数组中最小的数写入文件result,然后更新数组first_data(根据index读取该文件下一个数代替min_data);
- 判断是否所有数据都读取完毕,否则返回2。
多路归并程序的流程图:
第一步、Memory Sort。
第二步、Merge Sort。