这篇博客记录了《编程珠玑》第一章的对10^7数据量的磁盘文件排序。
一、问题描述:
输入:一个最多含有n个不重复的正整数(也就是说可能含有少于n个不重复正整数)的文件,其中每个数都小于等于n,且
n=10^7。
输出:得到按从小到大升序排列的包含所有输入的整数的列表。
条件:最多有大约1MB的内存空间可用,但磁盘空间足够。且要求运行时间在5分钟以下,10秒为最佳结果。
二、分析问题
用位向量表示10 000 000个整数需要10 000 000个位,10000000 bits = 1.192MB.所以程序员可利用的1MB空间是显然不够的,
可以采用两趟算法,第一趟利用5000000个位来排序0~4999999之间的整数,然后在第二趟中排序排序5000000~9999999之间的整数。
即:k趟算法可以在kn的时间开销和n/k的空间开销内完成对最多n个小于n的无重复正整数的排序。
三、代码
#include<iostream>
#include<stdio.h>
#include<bitset>
#include<fstream>
using namespace std;
const int MAX=500;
bitset<MAX+1> bit;
int main() {
int num,i;
ifstream infile;
infile.open("E:\\ZTE\\Number.txt");
if (infile.is_open()) {
while (infile.good() && !infile.eof()) {
infile >> num;
if (num <= MAX)
bit.set(num, 1);
else if (num > 2 * MAX) {
cout << "输入数据超出范围" << endl;
return 0;
}
}
for (i = 0;i < MAX + 1;++i) {
if (bit[i] == 1) {
cout << i << endl;
bit.reset(i);
}
}
}
else
cout << "can't open the file" << endl;
infile.close();
infile.open("E:\\ZTE\\Number.txt");
if (infile.is_open()) {
while (infile.good() && !infile.eof()) {
infile >> num;
if (num > MAX)
bit.set(num-MAX, 1);
else if (num > 2 * MAX) {
cout << "输入数据超出范围" << endl;
return 0;
}
}
for (i = 0;i < MAX+1;++i) {
if (bit[i] == 1) {
cout << i+MAX << endl;
bit.reset(i);
}
}
}
infile.close();
system("pause");
return 0;
}
其中读取的txt文件,是随机产生的,其代码如下:
#include<iostream>
#include<time.h>
#include<fstream>
using namespace std;
const int N = 10000000;
int arr[N];
void _swap(int& a, int& b) {
int t = a;
a = b;
b = t;
}
int _rand(int _min, int _max) {
return (rand() % (_max - _min + 1)) + _min;
}
int main() {
srand((unsigned int)time(NULL));
ofstream outfile;
outfile.open("E:\\ZTE\\Number.txt");
int i;
int k = N-1;
for (i = 0;i < N;++i)
arr[i] = i;
for (i = 0;i < k;++i) {
_swap(arr[i], arr[_rand(i + 1, N - 1)]);
}
/*
cout << "输出换序后的结果" << endl;
for (i = 0;i < N;++i) {
cout<<i<<": "<<arr[i]<<endl;
}
*/
if (outfile.is_open())
{
for (i = 0;i < N;++i) {
outfile << arr[i] << endl;
}
outfile.close();
}
else
{
cout << "不能打开文件!" << endl;
}
system("pause");
return 0;
}