問題:
輸入:乙個最多包含n個正整數的檔案,每個數都小於n(n=1000w)。如果在輸入檔案中有任何整數重複出現就是致命錯誤。沒有其他資料與該整數相關聯。
輸出:按公升序排列的輸入整數的列表。
約束:最多有(大約)1 mb的記憶體空間可用,有充足的磁碟儲存空間可用。執行時間最多幾分鐘,執行時間為10秒就不需要進一步優化了。
方法一:歸併排序。(耗時間)
歸併排序需把資料全部讀入記憶體,1000w個整數的大小是1000w*4/(1024*1024)大約是40m(假設乙個整數是4位元組),顯然不能將全部資料讀入記憶體。
方法二:分段排序。(耗時間)
將這些整數分成40組,分別是[0-249999] [250000-4999999] … [9750000-9999999],然後遍歷40次。這樣時間複雜度是40n,空間複雜度是n/40,比歸併要好點。當然也可以把範圍擴大或者縮小。
方法三:位圖法。
用1位來表示[0~n-1]中的整數是否存在。1表示存在,0表示不存在。這樣的話進行一次遍歷,就可以進行排序了,而且空間複雜度是n/(8*1024*1024)。例如對於20個數來說,如果集合是.那麼其位圖表示法如下:01110100100001000000(說明:左邊第一位表示 0 )。
程式:
利用bitset
#include
#include
#include
using namespace std;
int main()
for (i=0;i<1000000;++i)
} return 0;}
利用位邏輯運算
事實上,我們是用每乙個元素表示乙個32位的二進位制字串這樣這個元素可以保留相鄰32個號碼是否存在的資訊,陣列範圍就下降到了10000000/32了,例如對於號碼89256,由於89256 mod 32=2789…8,這樣我們應該 置a[2789]中32位字串的第8位(從低位數起)為1現在問題的關鍵是,如何用位邏輯運算來表示這種操作。
#include
#include
#define shift 5
#define mask 0x1f
#define n 10000000
int a[1 + n/32];
// 置位函式----用「|」操作符,i & mask相當於mod操作
//m mod n 運算,當n = 2 的x次冪的時候,m mod n = m & (n-1)
void set(int i)
void clr(int i)
int test(int i)
int main()
程式設計珠璣第一章
原文中的問題 如何在1mb的空間裡面對一千萬個整數進行排序?並且每個數都小於1千萬。實際上這個需要1.25mb的記憶體空間。1mb總共有838,8608。所以估計也可以在1mb左右的空間裡面進行排序了。include include define bitsperword 32 define shif...
程式設計珠璣第一章
下午看完程式設計珠璣第一章,感覺很不錯!如作者所說 閱讀本書乙個提示,不要太快,一次閱讀一章。集中精力思考,解答課後習題。寫總結就是在剛弄懂的時候,這時候是最恰當的時候,最容易接受。題目要求 乙個最多含有1000萬個整數的檔案,整數沒有重複,請輸出公升序排列。約束 最多1m記憶體,時間10s。題目很...
《程式設計珠璣》第一章筆記
文章從乙個實際的問題開始 乙個 系統,7位數的 號碼,用1mb的記憶體空間將這些 號碼排序。分析 如果將這些 號碼看成int型別的整數,將其讀入記憶體中進行排序,int型別4個位元組,最多有10000000個 號碼,則需要40mb的記憶體空間,遠遠超出題目的要求,但是這10000000個資料有他們的...