11如何給1千萬個資料量的磁碟檔案排序

2022-07-03 14:30:25 字數 3231 閱讀 6433

問題描述:

輸入:給定乙個檔案,裡面含有多個不重複的正整數,其中每個數都小於等於n,並且正整數的總個數小於n,n=10^7。

輸出:得到按從小到大公升序排列的包含所有輸入的整數的列表。

條件:最多有大約1mb

的記憶體空間可用,但磁碟空間足夠。且要求執行時間在5分鐘以下,10秒為最佳結果。

一:位圖法

因為所有整數均不重複,所以,考慮位圖法。位圖法就是當且僅當整數i在檔案中存在時,第i位置為1。

因為n = 10000000,所以總共需要n/8個位元組儲存,也就是10000000/8 = 1250000個位元組,大約1.25m,超過了記憶體限制。此時該如何處理呢?

可以分批處理,具體執行步驟如下

第一次,只處理0-4999999之間的資料,這些數都是小於5000000的,對這些數進行位圖排序,只需要約5000000/8=625000位元組,也就是0.625m,排序後輸出。

第二次,掃瞄輸入檔案時,只處理4999999-10000000的資料項,也只需要0.625m(可以使用第一次處理申請的記憶體)。

因此,總共也只需要0.625m。點陣圖的的方法有必要強調一下,就是點陣圖的適用範圍為針對不重複的資料進行排序,若資料有重複,位圖方案就不適用了。

**如下:

#define maxnum  10000000

void bit_set(unsigned char *bitset, int i)

int isbitseted(unsigned char *bitset, int i)

int size = (maxnum/2)/8 + 1;

int i;

bitset = malloc(size);

memset(bitset, 0, size);

file *fp = fopen(datafile, "r");

assert(fp);

file *res = fopen(resfile, "w");

assert(res);

while(fscanf(fp, "%d", &num) !=eof)

}for(i = 0;i < maxnum/2; i++)

}fseek(fp, 0, seek_set);

memset(bitset, 0, size);

while(fscanf(fp, "%d", &num) !=eof)

}for(i = 0; i < maxnum/2; i++)

}該演算法在cpu為pentium(r) dual-core e5500 2.80ghz上測試時間為6.359 sec

二:多路歸併

雖然位圖法清晰明了,但是限制條件較多。比如整數不能重複,整數值不能太大,如果不滿足這樣的條件怎麼辦?

分而治之,大而化小,也就是把整個大檔案分為若干大小的幾塊,然後分別對每一塊進行排序,最後完成整個過程的排序。這就是多路歸併演算法。

假設檔案中整數個數為n(n是億級的),整數之間用空格分開。首先分多次從該檔案中讀取m個整數,每次將m個整數在記憶體中使用快速排序之後存入臨時檔案,然後使用多路歸併將各個臨時檔案中的資料再次整體排好序後存入輸出檔案。顯然,該排序演算法需要對每個整數做2次磁碟讀和2次磁碟寫。

針對本題目,本程式由兩部分構成:

1:記憶體排序:

由於要求的可用記憶體為1mb,那麼每次可以在記憶體中對250k個資料進行排序,然後將有序的數寫入硬碟。那麼10m個資料需要迴圈40次,最終產生40個有序的檔案。

2:歸併排序:

將每個檔案最開始的數讀入(由於有序,所以為該檔案最小數),存放在乙個大小為40的first_data陣列中;

選擇first_data陣列中最小的數min_data,及其對應的檔案索引index,將first_data陣列中最小的數寫入檔案result,然後更新陣列first_data(根據index讀取該檔案下乙個數代替min_data)。直到所有40個檔案讀取完畢。

**如下:

#define filenum 40

#define maxnum  10000000

void memorysort()

else

buf = malloc(size);

assert(buf);

memset(buf, 0, size);

file *fp = fopen("data.txt","r");

assert(fp);

char filename[10] = {};

file *fileset[filenum+1] = ;

for(i = 1; i <= filenum; i++)  //建立開啟40個臨時檔案,檔名為:s1,s2,...,s40

i = 0;

j = 1;

k = 0;

while(fscanf(fp, "%d", &buf[i])!= eof)

i = 0;

fclose(fileset[j++]);

memset(buf,0, size);}}

if(i < (size/sizeof(int)) && i> 0)       //這是針對maxnum/filenum不能整除的情況。}}

void  externsort()

;int min, index;

int num = 0;

file *fileset[filenum+1] = ;

for(i = 1; i <= filenum; i++)

for(i = 1; i <= filenum; i++) 

//首先讀取每個檔案的第乙個數,放入陣列中。

}for(;;)

}fprintf(fout,"%d ", min);

//繼續讀取響應的檔案,更新

buf陣列

if(fscanf(fileset[index],"%d", &buf[index]) == eof)             }}

}該演算法在cpu為pentium(r) dual-core e5500 2.80ghz上測試時間為11.101 sec,頻繁的讀寫檔案造成了速度要比位圖法慢很多。

注意:上述程式在外部歸併排序的過程中,每次選擇最小值的時候總是將所有陣列元素進行比較,是一種最簡單的做法,其實可以建立敗者樹,使得總比較次數達到n*logk。

(

oracle千萬級資料量的表關聯更新

查詢資料庫中的鎖 select sess.sid,sess.serial lo.oracle username,lo.os user name,ao.object name,lo.locked mode from v locked object lo,dba objects ao,v session...

千萬級的資料量,我們的sql怎麼優化呢?

現在的公司資料量一般都比較大,當我們需要同此多個讀資料庫的操作,會出現什麼樣的情況呢?string sql insert into info id,name,age,card,otherinfo values i 我是第 i 個 i 100 dsfs i i 37 其他資訊 mysql.add sq...

完整的微博千萬級資料量思路過程

我也不喜歡說廢話,來救直接上,專案要求爬微博,存成四張表 分別是使用者資訊表,使用者和使用者關係表,微博資訊表,微博和微博關係表,改為分布式爬蟲可實現單日1000 的資料量,直接開始幹把準備 首先你的準備好幾百個微博賬號,並獲取cookie,樓主借鑑網上很多大神的方法,也是通過訪問手機端拿到cook...