第一章

  1. 如果不缺內存,如何使用一個具有庫的語言來實現一種排序算法以表示和排序集合。
    compare方法:
int compare(void const *a, void const *b){
    return *(int *)a- *(int *)b;
}

實現:

int n;
    scanf("%d",&n);
    int c[n];
    for (int i = 0; i < n; i ++) {
        scanf("%d",&c[i]);
        qsort(c, n, sizeof(int), compare);
    }
    for (int i = 0; i < n; i ++) {
        printf("%d",c[i]);
    }
  1. 如何使用為邏輯運算(如與、或、移位)來實現位向量。
    宏定義
#define BITSPERWORD 32
#define SHIFT 5
#define MASK 0x1F
#define N 10000000
#define K 1000000

全局變量聲明:

int a[1 + N/BITSPERWORD];

賦值函數:

//i>>SHIFT i右移5位,作為a的下標
//i & MASK int32位,確定在哪一位 
void set(int i){
    a[i>>SHIFT] |= (1<<(i & MASK));
}

清空函數:

//~(1<<(i & MASK)) 實際對i取反 &= 操作之后結果為00000
void clr(int i){
    a[i >> SHIFT] &= ~(1<<(i & MASK));
}

校驗函數:

int test(int i){
    return a[i >> SHIFT] & (1 << (i & MASK));
}
  1. 運行效率是設計目標的重要組成部分,所得到的程序需要足夠高效。在你自己的系統上實現位圖排序并度量其時間。該時間與系統排序的運行時間以及習題1排序運行的時間相比如何?假設n為10000000,并輸入文件包含1000000個整數。
    使用習題2的答案來實現排序算法。
for (int i = 0; i < N; i ++) {
        clr(i);
        while (scanf("%d",&i) != EOF) {
            set(i);
        }
    }
    for (int i = 0; i < N; i ++) {
        if (test(i)) {
            printf("%d\n",i);
        }
    }
  1. 如果認真考慮了習題3,你將會面對一個生成小于n且沒有重復的k個整數的問題。最簡單的方法就是使用前k個正整數。這個極端的數據集合將不會明顯地改變位圖方法的運行時間,但可能會扭曲系統排序的運行時間。如何生成位于0到n-1之間的k個不同的隨機栓恤的隨機整數?盡量使你的程序簡單且高效。
    生成隨機數的函數
int randint(int l,int u){
    int temp;
    srand((unsigned)time(NULL));
    temp = floor(l + (1.0*rand()/RAND_MAX)*(u - l + 1 ));
    return temp;
}

交換函數:

void swap(int *a,int *b){
    int t;
    t = *a;
    *a = *b;
    *b = t;
}

聲明全局變量narray

int narray[N];

實現:

//對narray賦值
for (int i = 0 ; i < N; i ++) {
        narray[i] = i;
    }
    //聲明karray
    int karray[K];
    //dui對karray賦值
    for (int i = 0; i < K; i ++) {
    //隨機打亂narray順序并對karray賦值
    swap(&narray[i], &narray[randint(i, N - 1)]);
        karray[i] = narray[i];
    }
    //清除
    for (int i = 0; i < N; i ++) {
        clr(i);
    }
    //賦值
    for (int i = 0; i < K; i ++) {
        set(karray[i]);
    }
    //校驗和輸出
    for (int i = 0; i < N; i ++) {
        if (test(i)) {
            printf("%d\n",i);
        }
    }
  1. 那個程序員說他有1MB 可用存儲空間,但是我們概要描述的代碼需要1.25MB的空間。他可以不費力氣的索取到額外的空間。如果1MB的空間是嚴格的邊界,你會推薦如何處理?你的算法的運行時間又是多少?
    使用位圖表示1000萬個數需要1000萬個位,或者說125萬字節考慮到沒有數字1和0開頭的電話號碼,我們可以將內存需求降低為100萬字節。另外一種做法是采用兩趟算法,首先用5000000/8=625000個字節的存儲空間來排序0-4999999之間的整數,然后在第二趟排序5000000-9999999的整數。k趟算法可以在kn的時間開銷和n/k的空間開銷內完成對最多n個小于n的無重復正整數的排序。
  2. 如果那個程序員說的不是每個文件最多出現1次,而是每個整數最多出現10次,你又如何建議他?你的解決方案如何隨著可用存儲空間的總量的變化而變化?
    如果每個整數最多出現10次,那我們可以使用4位的半字節來統計它出現的次數。利用習題5的答案,我們可以10000000/2個字節在1趟內完成對整個文件的排序,或者使用10000000/2k個字節在k趟內完成對整個文件的排序。

宏定義:

#define BITSPERWORD 16
#define SHIFT 3
#define MASK 0x07
#define N 10000000
#define K 1000000

函數:

void set(int i){
    a[i>>SHIFT] += (1<<(4 *(i & MASK)));
}

void clr(int i){
    a[i >> SHIFT] &= ~(0x0F<<(4*(i & MASK)));
}

int test(int i){
    return (a[i>>SHIFT] & (0x0F<<(4 *(i&MASK))))>>4*(i&MASK);
}

代碼測試:

int number[5] = {13,9,13,11,13};
    for (int i = 0; i < 5; i ++) {
        clr(number[i]);
    }
    
    for (int i = 0; i < 5; i ++) {
        set(number[i]);
    }

    printf("number==%d\n",test(13));
  1. 本書1.4節中描述的程序存在一些缺陷。首先是假定在輸入中沒有出現兩次的整數。如果某個數出現超過一次的話,會發生什么?在這種情況下,如何修改程序來調用錯誤處理函數?當輸入整數小于0或大于等于n時,又會發生什么?如果某個輸入不是數值又如何?在這種情況下,程序應該如何處理?程序還應該包含哪些明智的檢查?描述一些用以測試程序的小型數據集合,并說明如何正確處理上述以及其他的不良情況。
    可能我想的這些都是一些很淺顯的想法,但無論怎樣先記錄下來吧。
    如果整數超出一次的話,在保存的時候進行記錄。超出一次的后果第一次存儲的數據會被第二次的替換,排序總數少一個。
    當輸入的整數小于零或大于n時,排序相當于對n-1個整數排序。如果輸入的不是數值有可能會發生崩潰的情況比如輸入的是char類型字符,也有可能發生和輸入大于n小于0一樣的情況。這樣的情況下需要對輸入的信息進行判斷,當信息不準確的時候提示重新輸入或者結束當前程序。
    就先寫下了這么多。
  2. 當那個程序員解決gai該問題的時候,美國所有免費電話的區號都是800。現在免費的區號包括800、877、和888,而且還在增多。如果在1MB空間內完成對所有這些免費電話的排序?如何將免費電話號碼存儲在一個集合中,要求可以實現非常快速的查找以判定一個給定的免費電話號碼是否可用或者已經存在?
    隨機數的生成出現了一些問題,有時間再回來解決。
  3. 使用更多的空間來換取更少的運行時間存在一個問題:初始化空間本身需要消耗大量的時間。艘名如何設計一種技術,在第一次訪問向量時將其初始化為0。你的方案應該使用常量時間進行初始化和向量訪問,使用的額外空間正比于向量的大小。因為該方法通過進一步增加空間來減少初始化的時間,所以僅在空間很廉價、時間很寶貴且響亮很稀疏的情況下才考慮使用。
    借助于兩個額外的向量from、to和一個整數top,我們就可以使用表示來初始化向量data[0..n-1]。如果元素data[i]已經初始化,那么from[i]<top并且to[from[i]] = i。因此,from是一個簡單的標識,to和top一起確保了from中不會被寫入內存里的隨機內容。
    代碼展示:(不確定正確)
int nameArray[100000];
    int from[100];
    int to[100];
    int top = 2;
    from[80] = top;
    to[from[80]] = 80;
    nameArray[80] = 33;
    top ++;
  1. 在成本低廉的隔日送達時代之前,商店允許顧客通過電話訂購商品,并在幾天后上門自取。尚待你的數據庫使用客戶的電話號碼作為其檢索的主關鍵字(客戶知道他們自己的電話號碼,而且這些關鍵字幾乎都是唯一的)。你如何組織商店的數據庫,以允許高效的插入和檢索操作?
    商店將紙質的表格放在10*10的箱數組中,使用客戶電話號碼的最后兩位作為散列索引。當客戶打電話下訂單時,將訂單放到適當的箱中當客戶來取商品時,銷售人員順序搜索對應箱中的訂單-這就是經典的“用順序搜索來解決沖突中的開放散列”。電話號碼的最后兩位非常接近隨機,因此是非常理想的散列函數,而最前面的兩位數字很不理想。
  2. 載人航天的先驅們很快就意識到了需要在外太空的極端環境下實現順利的書寫。民間盛傳美國航天宇航局話費100萬美元研發出來了一種特殊的鋼筆來解決這個問題。那么,前蘇聯又會如何解決相同的問題呢?
    民間盛傳的美國宇航局話費100萬美元研發出來了這種鋼筆的信息是錯誤的。這種鋼筆確實是由美國的一個商人自費研發出來的,后賣給了美國宇航局使用。蘇聯據說也在使用這種鋼筆。這個故事可以告訴我們三個道理(1):不要被事物的表象迷惑。針對每一件事情而言,你都需要徹徹底底的融入進去知道每一步的每一個細節,知道每一步的每一個原因。沒有特別小的事情,很多時候一件事情涉及到了很多知識和智慧。再回頭可能不是我們當初想象的那么簡單。(2)對一件事情換一個思路可能會有不同的結果。更多的時候面對一件事情最重要的不是立即去做,而是要好好思考一下怎么去做。(3)無論做什么都要有自己的看法,不要被別人帶走了。對對的事情堅持和贊揚,對錯的事情避
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 背景 一年多以前我在知乎上答了有關LeetCode的問題, 分享了一些自己做題目的經驗。 張土汪:刷leetcod...
    土汪閱讀 12,775評論 0 33
  • 《速度與激情8》告訴我們:一個人干不過一個團隊,一個團隊干不過一個系統,一個系統干不過一個趨勢! 『團隊+系統+趨...
    享杰同學閱讀 767評論 0 0
  • 25歲的你,大學畢業不到五年。 相信在大學時,很多人都會設想自己的未來是什么樣的。可能有的人想當公務員,想掌握權力...
    當代坐家閱讀 284評論 1 1