问题描述:
问题:一个最多包含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
-
-
- 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];
- 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)]);
- 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.
整个程序的思想就是:
1.每个整数有32位,那么它就可以表示32个数,分别对应每bit位为1.
2.然后把10000000个数分为1+N/BITSPERWORD组(相当于有这么多个桶),每组包含接近32个数。
上面的解释可能仍不到位,那我们来看具体的函数:
对于set函数,我们可以这样理解arr[i>>SHIFT] |= (1<<(i&MASK))可以转化为arr[i/32] = arr[i/32] | (1<<(i%32))i%32必然处于区间[0, 31],那么1<<(i%32)就是将bit位1向前移动(i%32)位,然后和arr[i/32]相或,因而arr[i/32]的第(i%32)位就为1.
对于test函数,就是上面过程的反过程了。它是用来判断i个这个数是否存在,即arr[i/32]的相应bit位是否为1.
如下图:
最后,就做排序了, for (int i = 0; i < N; i++)由于[0, N)已经是从小到大排序好的,那么我们只需判断每个数是否存在,若存在,就输出,所以输出结果也就是排序的了。
- #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));
-
- }
-
- int test_i(int i)
- {
- return a[i>>SHIFT] & (1 << (i&MASK));
- }
-
- void clr_i(int i)
- {
- a[i >> SHIFT] &= ~(1<<(i&MASK));
- }
- 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)
- {
-
- 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;
- }
- }
-
-
- 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进行排序
- <pre name="code" class="cpp">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;</pre><br>
- <br>
- <p></p>
- <pre></pre>