1. 程式人生 > >[排序] 對檔案A.txt中儲存了N個整數進行排序(N大於100萬)要求僅佔用4K記憶體 - 點陣圖排序

[排序] 對檔案A.txt中儲存了N個整數進行排序(N大於100萬)要求僅佔用4K記憶體 - 點陣圖排序

【題目】檔案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.重複12操作,直到 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); }