【編程珠璣】第一章 開篇

來源:互聯網
上載者:User

一,題目:

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

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

二,分析:

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

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

        3)位元影像法,採用一個1千萬位的字串表示每個數,比如{0,2,3}表示為   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 <stdio.h>#include <stdlib.h>#define SHIFT 5#define MASK 0x1F#define N 10000000int a[1 + N/32];void set(int i) {        a[i>>SHIFT] |=  (1<<(i & MASK)); }void clr(int i) {        a[i>>SHIFT] &= ~(1<<(i & MASK)); }int  test(int i){ return a[i>>SHIFT] &   (1<<(i & MASK)); }int main(){       int i = 0;        //int  top = 1 + N/BITSPERWORD;        //memset(a, 0, sizeof(a)*sizeof(int));        while (scanf("%d", &i)) set(i);        for (i = 0; i < N; i++)                if (test(i))    printf("%d\n", i);        return 0;}

四,課後的題目:

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

#include <stdio.h>  #include <stdlib.h>  #define ms 1025  int a[ms];  int cmp(const void *a, const void *b)  {      return (*(int*)a) - (*(int*)b);  }  int main(void)  {      int n, i;      while (scanf("%d", &n) != EOF)      {          for (i = 0; i < n; ++i) scanf("%d", &a[i]);                                qsort(a, n, sizeof(int), cmp);          for (i = 0; i < n - 1; ++i) printf("%d ", a[i]);          printf("%d\n", a[i]);      }      return 0;  }  

使用set容器

#include <iostream>#include <set>using namespace std;int main(){set<int> S;  //STL容器內部採用紅/黑樹狀結構作為排序資料結構int i;set<int>::iterator j;while(cin>>i)S.insert(i);for(j=S.begin();j!=S.end();++j)cout<<*j<<endl;return 0;}

2、使用位元運算

void set(int i) {  a[i>>SHIFT] |=  (1<<(i & MASK)); }  void clr(int i)  {  a[i>>SHIFT] &= ~(1<<(i & MASK)); }  int  test(int i) {   return a[i>>SHIFT] &   (1<<(i & MASK)); }  

 

3、比較位元影像排序與系統排序

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

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

 

for (i = 0; i < n; ++i)       a[i] = i;  for (i = 0; i < n; ++i)  {      pos = rand()%(n - i) + i;      t = a[i]; a[i] = a[pos]; a[pos] = t;  }  


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<stdio.h>  #include<stdlib.h>  #include<string.h>    #define ms 100  int a[ms];  int b[ms];  int c[ms];  int top;    //判斷是否被初始化過。  bool is_init(int i)  {      return (b[i] < top && c[b[i]] == i);  }  int main(void)  {      top = 0;  //這裡產生一些隨機數值。          for (int i = 0; i < ms; ++i)          a[i] = b[i] = c[i] = i;      for (int i = 0; i < ms; ++i)      {          if (is_init(i))          {              printf("error");          }          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)      {          if (is_init(i) == false)          {              a[i] = i;              b[i] = top;              c[top++] = i;          }      }        for (int i = 0; i < ms; ++i)      {          if (!is_init(i))          {              printf("error: %d\n", i);          }      }      return 0;  }  

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.