数据继续增加,麻烦很多。下面给出一个方案:
void shift(int data[], int i, int length) //筛选算法 { for(int c; c= i* 2+ 1, c< length; ) if(c+= c+ 1< length && data[c]< data[c + 1], data[i]<= data[c]) swap(data[c], data[i]), i= c; else break; } //---------------------- #define i1K 1024 #define i1M i1K* i1K #define BlockSize (100*i1M) void GetTopK(int sele, int All) { double times[3]= { GetTickCount() }; int *Data0= new int[sele], *Data1= new int[BlockSize], File0Number; String path= "D:\", name= "inFile.dat"; //第一步,打开或文件不存在时,做出随机数据文件。 if(File0Number= open(String(path+ name).c_str(), 0), File0Number== -1) { File0Number= creat(String(path+ name).c_str(), 2); for(int all= All, size= BlockSize; all> 0; all-= size) //减去做好的 for(int i= 0; i<= size; i++) if(i== size) _rtl_write(File0Number, Data1, min(size, all)); //写出一块数据 else Data1[i]= random(BlockSize); //得随机数 lseek(File0Number, 0, SEEK_SET); //回文件首 } times[0]= GetTickCount()- times[0]; times[1]= GetTickCount(); //第二步,取出数据。 _rtl_read(File0Number, Data0, sele); for(int i= (sele- 2)/ 2; i>= 0; i--) shift(Data0, i, sele); //建堆 for(int i, size= 1; size> 0; ) for(size= _rtl_read(File0Number, Data1, BlockSize), i= 0; i< size; i++) if(Data0[0]> Data1[i]) //小值 Data0[0]= Data1[i], shift(Data0, 0, sele); //加小值,再成堆 times[1]= GetTickCount()- times[1]; times[2]= GetTickCount(); //第三步,验证() //略 times[2]= GetTickCount()- times[2];
delete []Data0; delete []Data1; }
它先判断是否有原始数据文件。无则创建并写入随机数据。
再取出sele个数据。建最大堆。继续读出数据块。并逐步挑出最小数。
程序看起来,还是很简单的。但,有两个问题:
1、int 数的表达范围,只有二十亿。程序应该考虑数的表达范围问题了。
2、验证有麻烦:之前,我们①用标准排序与结果比较。②还可用结果中的最大数,与取值后余下的数做比较,要是得到这个最大数都小于或等余下的数,就证明结果是正确的。现在,数太多,没法用标准排序。而取数后的数,还是保留在原始数据中。也就不能用法②。
暂时就这样了。待想出验证办法再说。