问题描述:
问题:一个最多包含n个正整数的文件,每个数都小于n,n = 100 00000。文件中的正整数没有重复的,请按升序排列这些整数。可用内存空间只有1MB左右,运行时间在10秒左右。
选择方案:
1:归并排序,32为整数,1M的内存空间,每次可以读入约250 000(25万)个数(注意估计方法,1M 10的6次方,1百万字节,1G,10的9次方,10亿字节)
那就需要40次读入,第一次遍历文件,对0-249 999的树进行排序,第二次对250 000到499 999之间的数排序,瓶颈在于需要40次读入文件
2:利用位图和位向量解决,该排序的特征为:数据没有重复,数据限制在较小的范围内,除了单一整数外没有其他的相关数据了
习题:库语言实现排序
产生10 000 000文件
#include <iostream>
#include <ctime>
using namespace std;
#define RAND_MAX 10000
//rand 产生2^15次方的随机数,bigrand产生2^30次方的随机数,见编程珠玑12章如果用rand做产生的数据随机性不太好,所以用bigrand
int bigrand()
{
return (RAND_MAX)*rand()+rand();
}
int randint(int l,int u)
{
return l+ bigrand()%(u-l+1);
}
#define SOURCENUM 10000000
int testdata[SOURCENUM];//这么大的数组不能在main内定义,因为栈的大小有限制,定义为全局变量,在静态区
int main()
{
cout<<"shangglag"<<endl;
srand((unsigned)time(NULL));
for (int i = 0,j = 1; i < SOURCENUM; i++,j++)testdata[i] = j;
for(i = 0; i < SOURCENUM; i++)swap(testdata[i],testdata[randint(i,SOURCENUM-1)]);//rand()%(SOURCENUM-1 - i + 1)+i]
FILE* fp1 = fopen("D:\\file3.txt","w+");
if(!fp1)return 0;
for( i = 0; i <SOURCENUM; i++)
{
fprintf(fp1,"%d\n",testdata[i]);
if(i%10000)cout<<"-";
}
fclose(fp1);
}
采用位图的方法进行排序 参考http://www.cnblogs.com/shuaiwhu/archive/2011/05/29/2065039.html
首先弄懂i>>SHIFT相当于i/32,i&MASK相当于i%32.那么就采用这个,把a数组中的元素都设置为0.
整个程序的思想就是:
#include <iostream>
#include <ctime>
#include <set>
#include <bitset>
using namespace std;
#define BITSPERWORD 32
#define SHIFT 5
#define MASK 0x1f
#define N 10000000
int a[1+N/BITSPERWORD];
void set_i(int i)
{
a[i>>SHIFT] |= (1<<(i&MASK)); //a[i>>SHIFT] 每1个int32位为一个桶,a[i>>SHIFT]相当于找那个32位,
//1<<i(i&MASK),32位中中的那位为1
}
int test_i(int i)
{
return a[i>>SHIFT] & (1 << (i&MASK));//跟1与
}
void clr_i(int i)
{
a[i >> SHIFT] &= ~(1<<(i&MASK));//跟0与
}
int main()
{
for (int i = 0; i < (1+N/BITSPERWORD); i++ )
{
a[i] = 0;
}
FILE *fpin = fopen("D:\\file2.txt","r");
FILE *fpout = fopen("D:\\fpout.txt","w+");
int m = 0;
for (int i = 1; i <= N;i++)
{
if(fscanf(fpin,"%d",&m)==1)
{
//cout << m<<endl;
set_i(m);
}
}
for (int i = 1; i <= N;i++)//排序输出到文件
{
if (test_i(i))
{
fprintf(fpout,"%d\n",i);
}
}
fclose(fpin);
fclose(fpout);
system("pause");
return 0;
}
}
使用qsort函数进行排序,空间需求大30s
#include <iostream>
#include <ctime>
using namespace std;
int intcomp(const void *x,const void *y)
{
return *(int *)x - *(int *)y;//注意转型
}
#define N 10000000
int testdata[N];
int main()
{
clock_t beginTime,endTime;
beginTime = clock();
FILE *fpin = fopen("D:\\file4.txt","r");
FILE *fpout = fopen("D:\\fpout4.txt","w+");
int m = 0;
for (int i = 1; i <=N;i++)
{
if(fscanf(fpin,"%d",&m)==1)
{
testdata[i - 1] = m;
}
}
//void qsort(void *base, int nelem, int width, int (*fcmp)(const void *,const void *));
//参数:1、待排序数组首地址; 2、数组中待排序元素数量; 3、各元素的占用空间大小; 4、指向函数的指针,用于确定排序的顺序
qsort(testdata,10000000,sizeof(int),intcomp);
for (int i = 1; i <= N;i++)
{
fprintf(fpout,"%d\n",testdata[i-1]);
}
fclose(fpin);
fclose(fpout);
endTime = clock();
cout<<(double)(endTime - beginTime)/CLOCKS_PER_SEC<<endl;
}
用STLset进行排序
clock_t beginTime,endTime; beginTime = clock(); FILE *fpin = fopen("D:\\file4.txt","r"); FILE *fpout = fopen("D:\\fpout5.txt","w+"); int m = 0; set<int> S; for (int i = 1; i <=N;i++) { if(fscanf(fpin,"%d",&m)==1) { S.insert(m); } } set<int>::iterator siterator; for (siterator = S.begin();siterator!=S.end();++siterator) { fprintf(fpout,"%d\n",*siterator); } fclose(fpin); fclose(fpout); endTime = clock(); cout<<(double)(endTime - beginTime)/CLOCKS_PER_SEC<<endl;