[排序] 對檔案A.txt中儲存了N個整數進行排序(N大於100萬)要求僅佔用4K記憶體 - 點陣圖排序
阿新 • • 發佈:2018-11-12
【題目】檔案A.txt中儲存了N個整數(N大於100萬),要求僅佔用4K記憶體,對該檔案中的整數進行排序,結果輸出到B.txt
【思路】百萬級別的資料排序,理論上講,應該需要1M以上的空間。4k也可以做不過效率會差不少
4k位元組應該是32768個bit(4*1024*8)
申請4k記憶體,全部清零 遍歷A.txt中的整數,先對0~32767之間的資料進行處理 if 該數存在 該數對應的bit直1 遍歷4k記憶體的bit位,將對應bit為1的數輸出到結果檔案B.txt 4k記憶體清零 遍歷A.txt中的整數,對32768~62235之間的資料進行處理 if 該數存在 該數對應的bit直1 遍歷4k記憶體的bit位,將對應bit為1的數追加輸出到結果檔案B.txt 4k記憶體清零 如此往復重複上面的步驟,直到處理的資料涵蓋所有的資料範圍 最後B.txt中記錄了從小到大的所有資料排序,不會多,也不會少
【程式碼】C
【程式碼】C++
#include "stdio.h"
#include "malloc.h"
#include "time.h"
#include "assert.h"
#include <iostream>
#include <bitset>
using namespace std;//交換陣列中元素用的--忽略 可以手動交換
#define SIZE 2000000 //200萬
int num[SIZE]; //這個陣列是用來生成檔案A中資料用的
//生成檔案 A 200萬個資料 ----可以掠過不看
int genrand()
{
int n;
FILE *f=fopen("A.txt","w");
assert(f);
for(n=1;n<=SIZE;n++){//生成2000000個數字
num[n]=n;
}
srand((unsigned)time(NULL));//srand()用來設定rand()產生隨機數時的隨機數種子。
//引數seed必須是個整數,通常可以利用geypid()或time(0)的返回值來當做seed。
//如果每次seed都設相同值,rand()所產生的隨機數值每次就會一樣。
int i,j;
for(n=0;n<SIZE;n++){
i=(rand()*RAND_MAX+ rand())%SIZE;//rand()*RAND_MAX+rand() 是防止產生的隨機數最大值小於2000000
//rand()的範圍在0-2的16次方
j=(rand()*RAND_MAX+rand())%SIZE;
swap(num[i],num[j]);
}
for(n=0;n<SIZE;n++){
fprintf(f,"%d ",num[n]);//將陣列資料寫入檔案A中,以空格隔開
}
fclose(f);
return 0;
}
//const int max_each_scan=1024*2;//每次掃描4k記憶體,int 佔2個位元組
const int max_each_scan=1024*1024;//為了使效果明顯,這裡我多用了點空間。測試4K的話放開上面的程式碼,刪掉這句
int main(){
//***************** 資料定義 ***************
int num;//每次讀取的資料
//***************** 初始化操作 **************
genrand();//生成檔案A
clock_t begin=clock();//計時用的 忽略
bitset<max_each_scan> bit_map; //申請4k的點陣圖
bit_map.reset();
FILE *a=fopen("A.txt","r");
FILE *b=fopen("B.txt","w");
assert(a);//判斷a是否為空的 忽略
assert(b);
/****************** 核心程式碼 ****************
1.第一遍掃描A檔案 將0-2048數字對應下標的點陣圖置為1
2.將點陣圖為1的下標寫入B檔案中
3. 第二遍掃描 2048-4048...
4.重複1和2操作,直到 488個位圖(1000000/2048) ;
*/
for(int space=max_each_scan;space<SIZE+max_each_scan;space=space+max_each_scan){
fseek(a,0,0);//指標回指檔案A開頭
bit_map.reset();//點陣圖資料歸0
while(fscanf(a,"%d",&num)!=EOF){//讀取檔案A中資料,直到檔案末尾
if(num>=space-max_each_scan && num<space){//如果數字位於0-4K之間 (其實應該是0-4K的倍數,倍數就是迴圈的次數,第一次是0-4k,第二次是4K-8k...)
bit_map[num%max_each_scan]=1;//將點陣圖對應下標的資料置為1。 點陣圖就是0和1 組成的。
}
}
for(int i=1;i<=max_each_scan;i++){
if(bit_map[i]){//將點陣圖中該位對應是1的下標+當前搜尋的數字塊 寫入B檔案中
fprintf(b,"%d ",space-max_each_scan+i);
}
}
}
clock_t end = clock();//計時用的 忽略
printf("耗時:%d",(end-begin)/CLK_TCK);
fclose(a);
fclose(b);
}