程式設計珠璣 第一章 開篇

2021-08-26 21:39:57 字數 3523 閱讀 4881

一,題目:

如何在1mb的空間裡面對一千萬個整數進行排序?並且每個數都小於1千萬。實際上這個需要1.25mb的記憶體空間(這裡所說的空間是考慮用位圖表示法時,每一位代表乙個數,則1千萬/(1024*1024*8)約為1.25mb )。

1mb總共有838,8608個可用位。所以估計也可以在1mb左右的空間裡面進行排序了。

二,分析:

1)基於磁碟的歸併排序(耗時間)

2)每個號碼採用32位整數儲存的話,1mb大約可以儲存250 000 個號碼,需要讀取檔案40趟才能把全部整數排序。(耗時間)

3)位圖法,採用乙個1千萬位的字串表示每個數,比如表示為 1 0 1 1 0 0 0 0 。(說明:左邊第一位表示 0 第二位表示1 第三位表示 2 。如果有則表示為1,否則為0)遍歷每乙個整數,有則標記為1,否則標記為0。然後按順序輸出每個整數。這種方法實際需要1.25mb記憶體,如果可以方便弄到記憶體的話可以採用此種方法。

4)假如嚴格限制為1mb,可以採用的策略:兩次遍歷或者除去第一位為0或1的整數。

解釋:考慮到沒有以數字0或1開頭的**號碼,可以省略對這些數的操作。

兩次遍歷:對 1 ---4999 999之間的數排序,需要儲存空間為:5000 000/8 =625 000 位元組(8為乙個位元組中的位數)

對 5000 000 -10000 000 之間的數排序。

如果需要採用k趟演算法,方法類似。

三,原始碼:

#include #include #define shift 5

#define mask 0x1f

#define n 10000000

int a[1 + n/32];

void set(int i)

void clr(int i)

int test(int i)

int main()

四,課後的題目:

1、使用庫函式來進行排序

#include #include #define ms 1025  

int a[ms];

int cmp(const void *a, const void *b)

int main(void)

return 0;

}

使用set容器

#include #include using namespace std;

int main()

void clr(int i)

int test(int i)

3、比較位圖排序與系統排序

位圖排序是最快的,針對這個問題而言,qsort比stl sort速度快。

4、隨機生成[0, n)之間不重複的隨機數(關鍵思想為:先把所有可能數順序放到陣列,然後打亂順序,則保證不重複)

for (i = 0; i < n; ++i)   

a[i] = i;

for (i = 0; i < n; ++i)

5、如果1mb是嚴格控制的空間,如果資料有1.25mb的bit數目。那麼應該是需要讀取2次。

k = 需要跑幾趟直接用 需要排序的資料量/記憶體空間bit數,往上取整則可。

時間開銷 = kn

空間開銷 n/k

注意的是,每次在掃瞄的時候,取資料的範圍是不一樣的。

6、如果每個資料出現最多10次,那麼需要4個bit位來燒錄乙個數。這時儲存空間減小至原來的1/4。

那麼如果一定要按照bitmap的方式來進行處理,則需要利用5題中的結論。

7、問題:[r. weil]本書1.4 節中描述的程式存在一些缺陷。首先是假定在輸入中沒有出現兩次的整數。如果某個數出現超過一次的話,會發生什麼?在這種情況下,如何 修改程式來呼叫錯誤處理函式?當輸入整數小於零或大於等於n時,又會發生什麼?如果某個輸入不是數值又如何?在這些情況下,程式該如何處理?程式還應該包含 哪些明智的檢查?描述一些用以測試程式的小型資料集合,並說明如何正確處理上述以及其他的不良情況。

如果某個數出現超過一次的話,會發生什麼?

會被忽略掉, 因為原來的程式本身就是用來處理只出現一次的情況的。

在這種情況下,如何修改程式來呼叫錯誤處理函式?

while (scanf("%d", &i) != eof)  

if(test(i)) call_error_fun();

else set(i);

當輸入整數小於零或大於等於n時,又會發生什麼?

會出現訪問越界的情況。-1訪問時,會訪問a[-1]的31個bit位。

如果某個輸入不是數值又如何?在這些情況下,程式該如何處理?

輸入可能是浮點數,或是字元什麼的~~

可以先讀入字串,再用atoi轉換成為整形數,如果失敗,則進行出錯處理。

程式還應該包含哪些明智的檢查?

8、免費**號碼至少有800,878,888等,那麼如何檢視乙個號碼是否是免費號碼。?

第一種方案:如果是一千萬個**號碼都有可能成為免費號碼,那麼至需要1.25mb * (免費號碼字首個數)。

第二種方案:省空間,多次掃瞄檔案:

1、首先掃瞄整個檔案,看有哪個免費號碼字首。以及每個免費號碼字首下的號碼個數。

2、設定區間對映表:比如800字首有125個免費號碼,找到最大的數,與最小的數,差值做為bit長度。

第三種方案:建立索引的方式來進行處理。以最後7位為索引,後面800,878什麼的,為值。如果不是免費號碼,應該是不用加入到這個hash表中。

9、避免初始化問題

做法是:使用兩個等長的輔助陣列,比如要把a[n]初始化,那麼在第一次訪問時:

b[i] = top;

c[b[i]] = i;

++top;

給出示例**

#include#include#include#define ms 100  

int a[ms];

int b[ms];

int c[ms];

int top;

//判斷是否被初始化過。

bool is_init(int i)

int main(void)

int v = i + rand()%(ms - i + 1);

int t = a[i]; a[i] = a[v]; a[v] = t;

v = i + rand()%(ms - i + 1);

t = b[i]; b[i] = b[v]; b[v] = t;

v = i + rand()%(ms - i + 1);

t = c[i]; c[i] = c[v] ; c[v] = t;

} for (int i = 0; i < ms; ++i)

} for (int i = 0; i < ms; ++i)

} return 0;

}

程式設計珠璣 第一章開篇

遇到乙個提問 我們需要提出更多的細節問題,準確的把問題描述清楚,其次才是對問題進行設計解決 位圖 位向量 適用於 輸入資料限制在相對較小的範圍內 資料沒有重複 而且對於每條記錄而言,除了單一資料外,沒有任何其他關聯資料。但是依然可以靈活應用。原理總結 1.對小問題的仔細分析有時可以得到明顯的實際益處...

程式設計珠璣第一章

原文中的問題 如何在1mb的空間裡面對一千萬個整數進行排序?並且每個數都小於1千萬。實際上這個需要1.25mb的記憶體空間。1mb總共有838,8608。所以估計也可以在1mb左右的空間裡面進行排序了。include include define bitsperword 32 define shif...

程式設計珠璣第一章

下午看完程式設計珠璣第一章,感覺很不錯!如作者所說 閱讀本書乙個提示,不要太快,一次閱讀一章。集中精力思考,解答課後習題。寫總結就是在剛弄懂的時候,這時候是最恰當的時候,最容易接受。題目要求 乙個最多含有1000萬個整數的檔案,整數沒有重複,請輸出公升序排列。約束 最多1m記憶體,時間10s。題目很...