编程珠玑笔记第一章

问题描述:

问题:一个最多包含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文件

[cpp]  view plain copy
  1. #include <iostream>    
  2. #include <ctime>    
  3. using namespace std;  
  4. #define RAND_MAX 10000  
  5.   
  6. //rand 产生2^15次方的随机数,bigrand产生2^30次方的随机数,见编程珠玑12章如果用rand做产生的数据随机性不太好,所以用bigrand  
  7. int bigrand()  
  8. {  
  9.     return (RAND_MAX)*rand()+rand();  
  10. }  
  11. int randint(int l,int u)  
  12. {  
  13.     return l+ bigrand()%(u-l+1);  
  14. }  
  15. #define SOURCENUM 10000000  
  16. int testdata[SOURCENUM];//这么大的数组不能在main内定义,因为栈的大小有限制,定义为全局变量,在静态区  
  17. int main()  
  18. {  
  19.   
  20.     cout<<"shangglag"<<endl;  
  21.     srand((unsigned)time(NULL));  
  22.     for (int i = 0,j = 1; i < SOURCENUM; i++,j++)testdata[i] = j;  
  23.     for(i = 0; i <  SOURCENUM; i++)swap(testdata[i],testdata[randint(i,SOURCENUM-1)]);//rand()%(SOURCENUM-1 - i + 1)+i]  
  24.     FILE* fp1 = fopen("D:\\file3.txt","w+");  
  25.     if(!fp1)return 0;  
  26.     for( i = 0; i <SOURCENUM; i++)  
  27.     {  
  28.         fprintf(fp1,"%d\n",testdata[i]);  
  29.         if(i%10000)cout<<"-";  
  30.     }  
  31.     fclose(fp1);  
  32.   
  33. }  

采用位图的方法进行排序 参考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.
如下图:
编程珠玑笔记第一章_第1张图片
最后,就做排序了,      for (int i = 0; i < N; i++)由于[0, N)已经是从小到大排序好的,那么我们只需判断每个数是否存在,若存在,就输出,所以输出结果也就是排序的了。
[cpp]  view plain copy
  1. #include <iostream>  
  2. #include <ctime>  
  3. #include <set>  
  4. #include <bitset>  
  5. using namespace std;  
  6. #define BITSPERWORD 32  
  7. #define SHIFT 5  
  8. #define MASK 0x1f  
  9. #define N 10000000  
  10.   
  11. int a[1+N/BITSPERWORD];  
  12.   
  13. void set_i(int i)  
  14. {  
  15.     a[i>>SHIFT] |= (1<<(i&MASK)); //a[i>>SHIFT] 每1个int32位为一个桶,a[i>>SHIFT]相当于找那个32位,  
  16.                                    //1<<i(i&MASK),32位中中的那位为1  
  17. }  
  18.   
  19. int test_i(int i)  
  20. {  
  21.     return a[i>>SHIFT] & (1 << (i&MASK));//跟1与  
  22. }  
  23.   
  24. void clr_i(int i)  
  25. {  
  26.     a[i >> SHIFT] &= ~(1<<(i&MASK));//跟0与  
  27. }  
  28. int main()  
  29. {         
  30.         for (int i = 0; i < (1+N/BITSPERWORD); i++ )  
  31.     {  
  32.         a[i] = 0;  
  33.     }  
  34.         FILE *fpin = fopen("D:\\file2.txt","r");  
  35.     FILE *fpout = fopen("D:\\fpout.txt","w+");  
  36.     int m = 0;  
  37.     for (int i = 1; i <= N;i++)  
  38.     {  
  39.         if(fscanf(fpin,"%d",&m)==1)  
  40.         {  
  41.             //cout << m<<endl;  
  42.             set_i(m);  
  43.         }  
  44.     }  
  45.     for (int i = 1; i <= N;i++)//排序输出到文件  
  46.     {  
  47.         if (test_i(i))  
  48.         {  
  49.             fprintf(fpout,"%d\n",i);  
  50.         }  
  51.     }  
  52.     fclose(fpin);  
  53.     fclose(fpout);  
  54.         system("pause");  
  55.     return 0;  
  56. }  
  57. }  
 
 

使用qsort函数进行排序,空间需求大30s

[cpp]  view plain copy
  1. #include <iostream>  
  2. #include <ctime>  
  3. using namespace std;  
  4. int intcomp(const void  *x,const void *y)  
  5. {  
  6.     return *(int *)x - *(int *)y;//注意转型  
  7. }  
  8. #define N 10000000  
  9. int testdata[N];  
  10. int main()  
  11. {  
  12.     clock_t beginTime,endTime;  
  13.     beginTime = clock();  
  14.     FILE *fpin = fopen("D:\\file4.txt","r");  
  15.     FILE *fpout = fopen("D:\\fpout4.txt","w+");  
  16.     int m = 0;  
  17.     for (int i = 1; i <=N;i++)  
  18.     {  
  19.         if(fscanf(fpin,"%d",&m)==1)  
  20.         {  
  21.             testdata[i - 1] = m;  
  22.         }  
  23.     }  
  24.     //void qsort(void *base, int nelem, int width, int (*fcmp)(const void *,const void *));     
  25.     //参数:1、待排序数组首地址; 2、数组中待排序元素数量; 3、各元素的占用空间大小; 4、指向函数的指针,用于确定排序的顺序  
  26.     qsort(testdata,10000000,sizeof(int),intcomp);  
  27.     for (int i = 1; i <= N;i++)  
  28.     {  
  29.         fprintf(fpout,"%d\n",testdata[i-1]);  
  30.     }  
  31.     fclose(fpin);  
  32.     fclose(fpout);  
  33.     endTime = clock();  
  34.     cout<<(double)(endTime - beginTime)/CLOCKS_PER_SEC<<endl;  
  35. }  

用STLset进行排序
 
 
[cpp]  view plain copy
  1. <pre name="code" class="cpp">clock_t beginTime,endTime;  
  2.     beginTime = clock();  
  3.     FILE *fpin = fopen("D:\\file4.txt","r");  
  4.     FILE *fpout = fopen("D:\\fpout5.txt","w+");  
  5.     int m = 0;  
  6.     set<int> S;  
  7.     for (int i = 1; i <=N;i++)  
  8.     {  
  9.         if(fscanf(fpin,"%d",&m)==1)  
  10.         {  
  11.             S.insert(m);  
  12.         }  
  13.     }  
  14.     set<int>::iterator siterator;  
  15.     for (siterator = S.begin();siterator!=S.end();++siterator)  
  16.     {  
  17.         fprintf(fpout,"%d\n",*siterator);  
  18.     }  
  19.   
  20.     fclose(fpin);  
  21.     fclose(fpout);  
  22.     endTime = clock();  
  23.     cout<<(double)(endTime - beginTime)/CLOCKS_PER_SEC<<endl;</pre><br>  
  24. <br>  
  25. <p></p>  
  26. <pre></pre> 

你可能感兴趣的:(编程珠玑笔记第一章)