输入:给定一个文件,里面最多含有n个不重复的正整数(也就是说可能含有少于n个不重复正整数),且其中每个数都小于等于n,n=10^7。
输出:得到按从小到大升序排列的包含所有输入的整数的列表。
条件:最多有大约1MB的内存空间可用,但磁盘空间足够。且要求运行时间在5分钟以下,10秒为最佳结果。分析:下面咱们来一步一步的解决这个问题,
1、归并排序。你可能会想到把磁盘文件进行归并排序,但题目要求你只有1MB的内存空间可用,所以,归并排序这个方法不行。
2、位图方案。熟悉位图的朋友可能会想到用位图来表示这个文件集合。例如正如编程珠玑一书上所述,用一个20位长的字符串来表示一个所有元素都小于20的简单的非负整数集合,边框用如下字符串来表示集合
(1)位图方法,原理很简单,但是,主要学习c语言中的文件打开关闭,同时一定注意fseek啊,啊,啊,
1 //位图方法,适用于无重复,有一定范围的排序 2 //从1到10^7个数排序 3 //500万是0.625M分成两次 4 #include <iostream> 5 #include <ctime> 6 #include <bitset> 7 #include <assert.h> 8 using namespace std; 9 char * filepath="unsort.txt"; 10 char * filesort="sort.txt"; 11 #define max_each 5000000 12 #define size 10000000 13 14 int num[size+1]; 15 void createrandom() 16 { 17 FILE *fp = fopen("unsort.txt", "w"); 18 assert(fp); 19 int n; 20 for ( n = 1; n <= size; n++) 21 //之前此处写成了n=0;n<size。导致下面有一段小程序的测试数据出现了0,特此订正。 22 num[n] = n; 23 srand((unsigned)time(NULL)); 24 int i, j; 25 26 for (n = 0; n < size; n++) 27 { 28 i = (rand() * RAND_MAX + rand()) % 10000000; 29 j = (rand() * RAND_MAX + rand()) % 10000000; 30 swap(num[i], num[j]); 31 } 32 33 for (n = 1; n < size; n++) 34 fprintf(fp, "%d ", num[n]); 35 fclose(fp); 36 } 37 38 39 int main() 40 { 41 createrandom(); 42 clock_t begin=clock(); 43 bitset<max_each+1> bit; 44 bit.reset(); 45 FILE * unsort_file=fopen(filepath,"r"); 46 assert(unsort_file); 47 int num; 48 while(fscanf(unsort_file,"%d ",&num)!=EOF) 49 { 50 if(num<=max_each) 51 bit.set(num,1); 52 53 } 54 FILE * sort_file=fopen(filesort,"w"); 55 assert(sort_file); 56 for(int i=1;i<=max_each;i++) 57 if(bit[i]==1) 58 fprintf(sort_file,"%d ",i); 59 bit.reset(); 60 int result = fseek(unsort_file, 0, SEEK_SET); 61 if (result) 62 cout << "fseek failed!" << endl; 63 while(fscanf(unsort_file,"%d ",&num)!=EOF) 64 { 65 if(num>max_each) 66 { 67 num-=max_each; 68 bit.set(num,1); 69 } 70 } 71 for(int i=1;i<=max_each;i++) 72 if(bit[i]==1) 73 fprintf(sort_file,"%d ",i+max_each); 74 clock_t end=clock(); 75 cout<<"finish and usetime= "<<(end-begin)/CLK_TCK<<"s"<<endl; 76 fclose(sort_file); 77 fclose(unsort_file); 78 system("pause"); 79 }
归并排序方法:
吐血编程啊,防着july写的,单写还真写不对
1 //归并排序方法,采用多路归并,没有任何要求,什么样都能拍还是稳定的,就是要多次读写文件 2 //要求1m内存,而10的7次方个int是40M,要分成40个文件,一个文件1M,25万的数组为1M 3 #include <iostream> 4 using namespace std; 5 #include <ctime> 6 #include <assert.h> 7 #include <algorithm> 8 #define size 10000000 9 #define onesize 250000 10 11 int readtomem(FILE * fp,int * space) //读到内存时注意返回读了多少,最多到onesize单可能比那个小 12 { 13 int index=0; 14 while(index<onesize&&fscanf(fp,"%d ",&space[index])!=EOF) 15 { 16 index++; 17 } 18 return index; 19 } 20 21 void writetofile(FILE * fp,int * space,int num) //写的话是写多少个,返回空 22 { 23 for(int index=0;index<num;index++) 24 fprintf(fp,"%d ",space[index]); 25 } 26 27 string newfilename(int n) //起名字 28 { 29 char na[128]; 30 sprintf(na,"data%d.txt",n); 31 return na; 32 } 33 34 int memsort() //返回多少个文件 35 { 36 int count=0; 37 FILE * fp=fopen("unsort.txt","r"); 38 assert(fp); 39 int * space=new int[onesize]; 40 while(true) 41 { 42 int read=readtomem(fp,space); 43 if(read==0) 44 break; 45 sort(space,space+read); 46 count++; 47 string file=newfilename(count); 48 FILE * fpout=fopen(file.c_str(),"w"); //file.c_str()将string转换成char *。 49 assert(fpout); 50 writetofile(fpout,space,read); 51 fclose(fpout); 52 } 53 fclose(fp); 54 delete[] space; //注意是delete[],而不是delete,前面有题写错了 55 return count; 56 } 57 58 void merge_sort(int file_count) 59 { 60 if(file_count<=0) 61 return; 62 FILE **file_array=new FILE*[file_count]; //FILE×× 63 assert(file_array); 64 FILE * fp_result=fopen("memert_sort.txt","w"); //fopen以w可以创建文件 65 assert(fp_result); 66 for(int i=0;i<file_count;i++) 67 { 68 string file=newfilename(i+1); //注意i+1 69 file_array[i]=fopen(file.c_str(),"r"); 70 } 71 bool *finish=new bool[file_count]; 72 int * result=new int[file_count]; 73 memset(finish,false,sizeof(bool)*file_count); 74 for(int i=0;i<file_count;i++) 75 { 76 fscanf(file_array[i],"%d ",&result[i]); 77 } 78 while(true) 79 { 80 int index=0; 81 while(index<file_count&&finish[index]) //判断退出条件,当finish全是true时,退出,跳过那些已经空的文件 82 index++; 83 if(index==file_count) 84 break; 85 int min=result[index]; 86 int min_index=index; 87 for(int i=index+1;i<file_count;i++) 88 { 89 if(!finish[i]&&result[i]<min) //因为中间也有可能有空的,一般最后也有空的 90 { 91 min=result[i]; 92 min_index=i; 93 } 94 } 95 fprintf(fp_result,"%d ",min); 96 if(fscanf(file_array[min_index],"%d ",&result[min_index])==EOF) 97 { 98 finish[min_index]=true; 99 } 100 } 101 fclose(fp_result); 102 delete []finish; 103 delete []result; 104 for (int i = 0; i < file_count; i++) 105 fclose(file_array[i]); 106 delete [] file_array; 107 } 108 109 int main() 110 { 111 clock_t start_memory_sort = clock(); 112 int aux_file_num = memsort(); 113 clock_t end_memory_sort = clock(); 114 cout << "The time needs in memory sort: " << end_memory_sort - start_memory_sort << endl; 115 clock_t start_merge_sort = clock(); 116 merge_sort(aux_file_num); 117 clock_t end_merge_sort = clock(); 118 cout << "The time needs in merge sort: " << end_merge_sort - start_merge_sort << endl; 119 system("pause"); 120 return 0; 121 }