1. 程式人生 > >素數之篩法

素數之篩法

篩法

篩素數的常用手段:

1、Eratosthenes 篩法

複雜度:O(n log (log n))

從小到大找到一個素數,篩掉所有它的倍數。

程式碼:

 1 void Prim(int n)
 2 {
 3     //Eratosthenes篩選法
 4     memset(check,false,sizeof(check));
 5     int tot = 0;
 6     for(int i = 2;i  <= n;i ++)
 7         if(!check[i])
 8         {
 9             prim[tot++] = i;
10 for(int j = 2*i;j <= n;j += i) 11 check[j] = true; 12 } 13 }
View Code

 

 

2、Euler 篩法(重要!!!)

複雜度:O(n)

鑑於前者演算法的優化,因為上面的演算法一個非素數可能會被多個質因數篩多次,浪費了,所以優化掉這個,只用一個數最小的質因數排除(篩掉)這個數字。

 

 1 void Euler_prim(int n)
 2 {
 3     //尤拉篩選法     避免上面篩選法中的重複篩選
4 memset(check,false,sizeof(check)); 5 int tot = 0; 6 for(int i = 2;i <= n;i ++) 7 { 8 if(!check[i]) prim[tot ++] = i; 9 for(int j = 0;j < tot;j ++) //遍歷已經找到的素數 10 { 11 if(i * prim[j] > n) break; //後面相乘已經超出 n 的範圍,沒有查詢的必要了 12 check[i * prim[j]] = true
; //表示這個數字不是素數 13 if(i % prim[j] == 0) break; 14 } 15 } 16 }

 

 

重點解釋下 if (i%prim[j]==0) break 這句話:

因為prim[j]是i的最小質因數了,如果這時候繼續篩下去,下一個數為i*prim[j+1],因為 i=prim[j]*k,對於這個數來說最小質因數是prim[j],而這時卻要用prim[j+1]來篩,則與我們要達到的要求、效果違背,這個數肯定會在以後被Prim[j]篩掉,所以直接break就行了,後面的肯定也會被prim[j]篩掉。

(不知道這樣理解對不對。。。)

 

 

 

 

 

fighting fighting fighting !!!