素數篩法【Sieve Of Eratosthenes + Sieve Of Euler】

拖了有段時間,今天來總結下兩個常用的素數篩法:

1、sieve of Eratosthenes【埃氏篩法】

這是最簡單樸素的素數篩法了,根據wikipedia,時間複雜度爲 O(n \log\log n),空間複雜度爲O(n)。

算法思想:先假定所有的數都是素數,然後從最小的素數2出發,把素數的所有倍數篩出去。又因爲一個數的質因數都是成對出現的,比如100 = 1*100 = 2*50 = .....= 10*10,所以篩素數時只用篩到 n的開平方就行了。

僞代碼如下:


對於任意的範圍n,

設bool prime[ ],初始化 2→n 的元素爲false,

for(i=2; i < sqrt(n); i+++)

   if (!prime[ i ])

      for(j = i*i;  j * i < n; j+=i)

           prime[ j ] = false

 

2、sieve of Euler【歐拉線性篩】

儘管把埃氏篩法“優化”到n的開平方,但是還是做了很多重複的工作,比如 合數 6,它就會被2,和3重複篩出。

根據“每個整數都可以分解成它的 質因數之積”,因此每個數只需要被它的最小質因數篩除。

由上可以得到線性時間複雜度的篩法,歐拉篩法。

算法思路:

歐拉篩是個以空間換時間的算法,用prime[ ]數組記錄素數,初始bool數組is_prime[ ]爲false記錄每個數是否是素數,

僞代碼如下:

k = 0

for(i = 2; i < n; i++)

    if(!is_prime[i])

      prime[k++] = i

   for(j = 0; j < k&&i * prime[ j ]; j++)

      is_prime[i*prime[ j ]] = true;

     if(i % prime[ j ]) break;    //關鍵步驟。在此的prime[ j ]一定是i的最小質因子,you can gusse why~0-0

  【以下是實現代碼,外加兩種算法在時間上的比對】

#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstring>
using namespace std;
const long long maxn = 100000000;
bool  is_prime[maxn];
int EUprime[maxn];
bool ERprime[maxn];

int euler(int n){
   int k = 0;
   memset(is_prime,false, sizeof(is_prime));
   for(int i = 2; i <= n; i++){
    if(!is_prime[i])
        EUprime[k++] = i;
    for(int j = 0; j < k&&i * EUprime[j] <= n; j++){
        is_prime[i*EUprime[j]] = true;
        if(i % EUprime[j] == 0) break;
    }
   }
   return k;
}

int eratosthense(int n){
    int k = 0;
    memset(ERprime,false,sizeof(ERprime));
    for(int i = 2; i * i <= n; i++){
        if(!ERprime[i]){
            for(int j = i*i; j <= n; j+=i){
                ERprime[j] = true;
            }
        }
    }
    for(int i = 2; i <= n; i++)
    if(!ERprime[i]) {k++;}
    return k;
}

int main(){
    //int n;
    clock_t st,ed;
    double sec;
    for(int i = 10; i < 1000000000; i *= 10){
      cout<<i<<":"<<endl;
        int res;
        st = clock();
        res = eratosthense(i);
        ed = clock();
        sec = (double)(ed - st) / (double) CLOCKS_PER_SEC;
        printf("eratosthense :\t\t%8d\t%.8lf\n", res, sec);

        st = clock();
        res = euler(i);
        ed = clock();
        sec = (double)(ed - st) / (double) CLOCKS_PER_SEC;
        printf("Euler :\t\t%16d\t%.8lf\n", res, sec);

    }
}


【可以看到在小數據上兩個算法效率差別不大,在大數據情況下,Euler篩法的效率明顯比埃氏篩法高】


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章