求素數個數(埃氏篩法和尤拉篩法)
阿新 • • 發佈:2019-01-07
求1——n的素數的個數,有以下三種方法:
普通的O()演算法:
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
bool isprime(int x)
{
if(x<=1)
return false;
for(int i=2;i<=sqrt(x+0.5);++i)//+0.5是為了防止精度誤差
if(x%i==0) return false;
return true;
}
一般來說上面這個已經蠻不錯了,可是當n特別大,10^9以上時就有點力不從心了。我們有了下面的埃氏篩法。
埃氏篩法
複雜度:O(loglogn)
埃氏篩法的核心思想就是當我們找到一個素數,那麼這個數小於n的所有倍數肯定都不是素數,同時進行標記。
bool prime[maxn];//prime[i]為true表示i為質數 void init() { for(int i=2;i<maxn;i++)//初始化 prime[i]=true; for(int i=2;i<maxn;++i) { if(prime[i]) for(int j=2*i;j<maxn;j+=i)//把所有i的倍數都進行標記 { prime[j]=false; } } }
尤拉篩法
複雜度O(n)
尤拉篩法優化的一點就是改進了埃氏篩法的一點冗餘:可以發現,在埃氏篩法中,我們對每一個n都標記了不止一次。比如10,當i=2時,10作為2的倍數被標記一次,當i=5時,10依然是5的倍數,又被多餘的標記一次。
尤拉篩法思想:
其基礎是 “任何一個合數都可以由兩個質數相乘得到” 。那麼對於每一個n我們都可以用比它小的某一個質數來標記。
bool isprime[maxn];//isprime int primelistl[maxn];//primelist int n; int cnt=0; scanf("%d",&n); for(int i=1;i<=n;++i) isprime[i]=true; for(int i=2;i<=n;++i) { if(isprime[i]) { cnt++; //找到一個素數+1 primelist[cnt]=i; //把這個素數新增到素數表裡 } for(int j=1;j<=cnt;++j) //去列舉所有可以到達的質數 { if(i*primelist[j]>n) //如果已經大於n則break break; isprime[i*primelist[j]]=false; if(i%primelist[j]==0) //找到的是最小的質因子 break; } } printf("%d\n",cnt);