1. 程式人生 > 實用技巧 >線性篩法求質數

線性篩法求質數

數尋找時,開始最普遍的思路就是雙重迴圈暴力列舉,時間複雜度O(N),複雜度通常比較高,最可怕的是當資料範圍特別大的時候(1e),於是就需要像尤拉篩O(N)與埃氏篩O(nloglog)這樣的演算法。

埃氏篩法

又稱為Eratosthenes篩法(埃拉託斯特尼),簡單來講就是找到一個質數x,然後成倍2x,4x,6x......這樣來進行查詢,找到一個數就標記,沒標記的肯定是質數。
埃氏篩法的基本思想 :一般從2開始,將每個質數的倍數標記成合數,以達到篩選質數的目的。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 bool prime[100005
]; 4 int n; 5 void primes(int n){ 6 for(int i = 2; i <= n; i++) if(!prime[i]){ 7 cout << i << " "; 8 for(int j = 2 * i; j <= n; j += i)prime[j] = true; 9 } 10 } 11 int main(){ 12 cin >> n; 13 primes(n); 14 return 0; 15 }

發現2和3都對6進行了更新.所以我們可以進行優化,第二層迴圈的下限改成一下。

for(int j = i; j <= n / i; j++){
            prime[i * j] = true;
    }

埃氏篩法缺陷:對於一個合數,有可能被篩多次。例如10=110=25那麼如何確保每個合數只被篩選一次?我們只要用它的最小質因子來篩選即可。

尤拉篩法

這個演算法建立在埃氏篩法之上,用它的最小質因子來篩選,可以達到不重複的目的。
當x、y不互質時,若x是y的最小質因數,則e(xy)=e(y)+1。

#include <bits/stdc++.h>
#define maxn 100000
int s[maxn],prime[maxn],i,j,cnt; //
初始化素數 void Prime(){ for(i = 2;i<=maxn;i++) { if(!s[i]) prime[++cnt] = i;//記錄素數個數 for(j = 1; j <= cnt && i*prime[j] <= maxn; j++){ s[i*prime[j]] = 1; if(i % prime[j] == 0) break; } } }

保證每個數只被篩選一次:if(i % prime[j] == 0)break;// 保證了一個數只被篩一次。

這條語句保證了,每一個合數都只被篩除一次。為什麼呢?由於 i % prime[i] == 0 ,那麼如果繼續篩下去,i * prime[j+1]一定也會是某一個合數,那麼如果下一次判斷這個合數的時候,它依然會被prime[j] 篩掉.
雖然尤拉篩快,但複雜度高,容易RE。