歐拉篩法


埃拉托斯特尼篩法可以在 O(nloglogn)的復雜度內篩出素數,但事實上歐拉篩(線性篩)可以達到O(n)的線性效率!

先來看歐拉篩的算法及實現,然后再思考埃氏篩法時間都多在哪了。

歐拉篩算法步驟:

1.如果上界小於2,沒有素數,返回。

2.標記i=2為第一個素數。然后如果沒有到達上界,轉移到步驟3,否則轉移到步驟5。

3. 令i自增1。檢驗i是否是素數,如果是素數,將其填入素數數組中,轉移到步驟4。

4.,無論它是不是素數,都將它與目前已經找到的素數的乘積判定為合數。如果某一個素數可以被當前這個數 i 整除,或者所有已經選出的素數都已經遍歷過,或者當前素數*i后大於上界,轉移到步驟5。

5.到上界后,返回。否則轉移到步驟3。

 1 #include <iostream>
 2 #include <vector>
 3 using namespace std;
 4 void get_prime(vector<int> & prime,int upper_bound){ // 傳引用
 5     if(upper_bound < 2)return;
 6     vector<bool> Is_prime(upper_bound+1,true);
 7     for(int i = 2; i <= upper_bound; i++){
 8         if(Is_prime[i])
 9             prime.push_back(i);
10         for(int j = 0; j < prime.size() and i * prime[j] <= upper_bound; j++){
11             Is_prime[ i*prime[j] ] = false;
12             if(i % prime[j] == 0)break;// 保證了一個數只被篩一次。
13         }
14     }
15 }
16 int main(){
17     vector<int> prime;
18     get_prime(prime, 10000001);
19     for(vector<int> :: iterator it = prime.begin(); it not_eq prime.end(); it++)
20         cout<<*it<<" ";
21     return 0;
22 }

可以看出,歐拉篩法和埃氏篩法的主要不同之處有兩點:

1.篩選方式不同:埃氏篩法是針對每一個素數z,一次性篩除z的所有倍數。而歐拉篩法則是一步步篩掉一個素數的倍數。

看看埃氏篩法的時間都多在哪了?比如數6,它被2、3重復篩除了兩次。數42,被2、3、7篩過三次。那么不妨將n個素數相乘,對於這個乘積,我們一共多篩了n-1次!如何避免這種多余的工作呢?看下一條。

2.歐式篩法的關鍵特別之處在於一條語句: if(i % prime[j] == 0)break; 這條語句保證了,每一個合數都只被篩除一次。為什么呢?由於  i % prime[i] == 0 ,那么如果繼續篩下去,i * prime[j+1]一定也會是某一個合數,那么如果下一次判斷這個合數的時候,它依然會被 prime[j] 篩掉。雖然prime[j+1] 也可以篩除它,不過它已經被prime[j]篩過了,prime[j+1]的篩除工作是多余的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM