線性篩法求素數

來源:互聯網
上載者:User

標籤:style   blog   http   color   strong   os   

題目:給出一個正整數n,列印出所有從1~n的素數(即質數);

 

關鍵是要找出一個判斷一個正整數n是否為素數的方法...

 

傻瓜解法--n,n/2

 1 #include<stdio.h> 2 int main() 3 { 4   int i,n; 5   while(scanf("%d",&n)==1) 6   { for(i=2;i<n;i++) 7          if(n%i==0)    break;  8     if(i==n)    printf("YES\n"); 9     else           printf("NO\n");10   }11 }

這是理所當然的想法,按照素數的定義,除了1和它本身沒有其他的因數,就是素數。

這種解法的缺點就是紅色標註那裡,i<n,或者有的是i<n....這種迴圈規模n稍微大點,已耗用時間不談了,都是淚...

 

 

普通解法--sqrt(n)

 1 #include<stdio.h> 2 #include<math.h> 3 int main() 4 { int i,n,x; 5   while(scanf("%d",&n)==1) 6   { x=(int)sqrt(n); 7     for(i=2;i<=x;i++) 8          if(n%i==0)    break;  9     if(i>x)    printf("YES\n");10     else           printf("NO\n");11   }12 }

這裡迴圈取到sqrt(n),效率改進不少了...但顯然還是不夠理想....繼續往下看

 

普通篩選法--埃拉托斯特尼篩法

先簡單說一下原理:

基本思想:素數的倍數一定不是素數
實現方法:用一個長度為N+1的數組儲存資訊(0表示素數,1表示非素數),先假設所有的數都是素數(初始化為0),從第一個素數2開始,把2的倍數都標記為非素數(置為1),一直到大於N;然後進行下一趟,找到2後面的下一個素數3,進行同樣的處理,直到最後,數組中依然為0的數即為素數。
說明:整數1特殊處理即可。

舉個例子,N=20時,示範如:

最後數組裡面還是0的就是素數了...

代碼實現如下:

prime[]用來儲存得到的素數 prime[] = {2,3,5,7,11,.........} tot 是當前得到的素數的個數 check :0表示是素數  1表示合數

 1 memset(check, 0, sizeof(check)); 2 int tot = 0; 3 for (int i = 2; i <= n; ++i) 4 { 5   if (!check[i]) 6   { 7     prime[tot++] = i; 8   } 9   for (int j = i+i; j <= n; j += i)10   {11     check[j] = 1;12   }13 }

此篩選法的時間複雜度是O(nloglogn) 空間複雜度是O(n)

不足之處也比較明顯,手動類比一遍就會發現,很多數被處理了不止1遍,比如6,在素數為2的時候處理1次,為3時候又標記一次,因此又造成了比較大的不必要處理...那有沒有改進的辦法呢...就是下面改進之後的篩法...

 

 

線性篩法--歐拉篩法

先上代碼吧...

 1 #include<cstdio> 2 #include<cstring> 3 #define MAXN 100005 4 #define MAXL 1299710 5 int prime[MAXN]; 6 int check[MAXL]; 7  8 int tot = 0; 9 memset(check, 0, sizeof(check));10 for (int i = 2; i < MAXL; ++i)11 {12   if (!check[i])13   {14     prime[tot++] = i;15   }16   for (int j = 0; j < tot; ++j)17   {18     if (i * prime[j] > MAXL)19     {20       break;21     }22     check[i*prime[j]] = 1;23     if (i % prime[j] == 0)24     {25       break;26     }27   }28 }

精華就在於紅色標註那兩處,它們保證每個合數只會被它的最小質因數篩去,因此每個數只會被標記一次,所以時間複雜度是O(n)

還是按上面的例子進行一遍類比:N=20

此過程中保證了兩點:

1、合數一定被幹掉了...

2、每個數都沒有被重複地刪掉

(證明 見參考資料)

 

引申--求歐拉函數

在數論,對正整數n,歐拉函數是小於或等於n的數中與n互質的數的數目。此函數以其首名研究者歐拉命名,它又稱為Euler‘s totient function、φ函數、歐拉商數等。 例如φ(8)=4,因為1,3,5,7均和8互質。

求歐拉函數的方法只需在上面的程式中稍有改動即可,此處只貼出代碼:

 1 #include<cstdio> 2 #include<cstring> 3 #define MAXN 100005 4 #define MAXL 1299710 5 int prime[MAXN]; 6 int check[MAXL]; 7 int phi[MAXL]; 8 int tot = 0; 9 phi[1] = 1;10 memset(check, 0, sizeof(check));11 for (int i = 2; i < MAXL; ++i)12 {13   if (!check[i])14   {15     prime[tot++] = i;16     phi[i] = i - 1;17   }18   for (int j = 0; j < tot; ++j)19   {20     if (i * prime[j] > MAXL)21     {22       break;23     }24     check[i*prime[j]] = 1;25     if (i % prime[j] == 0)26     {27       phi[i*prime[j]] = phi[i] * prime[j];28       break;29     }else30     {31       phi[i*prime[j]] = phi[i] * (prime[j]-1);32     }33   }34 }

若是素數,那麼從1~n-1都是和它互質的數,所以phi(i) = i - 1;

另外兩個是積性函數(見參考資料)的公式和歐拉函數的特性。

 

參考資料

1、http://suno.cnblogs.com/

2、http://wenku.baidu.com/view/1187eebce009581b6ad9eb12

3、http://blog.csdn.net/dinosoft/article/details/5829550

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.