埃氏筛法
埃氏筛法是一种效率比较高的判断素数的方法。
可以求出n以内的所有素数,并返回素数个数,复杂度为 O ( n l o g l o g n ) O(nloglogn) O(nloglogn)。
原理
要得到自然数n以内的全部素数,必须把不大于 n \sqrt n n的所有素数的倍数剔除,剩下的就是素数。
给出要筛数值的范围n,找出以内的素数。
先用2去筛,即把2留下,把2的倍数剔除掉;再用下一个质数,也就是3筛,把3留下,把3的倍数剔除掉;接下去用下一个质数5筛,把5留下,把5的倍数剔除掉;不断重复…
代码实现:
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 1e5 + 5;
typedef long long ll;
int prime[N];
bool is_prime[N];
int sieve(int n)
{
int cnt = 0;
for (int i = 2; i <= n; i++)
is_prime[i] = 1;
is_prime[0] = is_prime[1] = 0;
for (ll i = 2; i <= n; i++){
if (is_prime[i]){
prime[cnt++] = i;
for (ll j = i * i; j <= n; j += i)
is_prime[j] = 0;
}
}
return cnt;
}
int main(void)
{
int n, cnt;
cin >> n;
cnt = sieve(n);
cout << cnt << endl;
for (int i = 0; i < cnt; i++){
cout << prime[i] << " ";
}
cout << endl;
for (int i = 0; i <= n; i++){
if (is_prime[i]){
cout << i << " ";
}
}
cout << endl;
return 0;
}
欧拉筛法
时间复杂度为 O ( n ) O(n) O(n)
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 1e5 + 5;
bool vis[N];
int prime[N];
int sieve(int n)
{
int cnt = 0;
for (int i = 0; i <= n; i++)
vis[i] = false;
for (int i = 2; i <= n; i++) {
if (!vis[i])
prime[cnt++] = i;
for (int j = 0; i * prime[j] <= n; j++) {
vis[i * prime[j]] = true;
if (i % prime[j] == 0)
break;
}
}
return cnt;
}
int main(void)
{
int n, cnt;
cin >> n;
cnt = sieve(n);
cout << cnt << endl;
for (int i = 0; i < cnt; i++)
cout << prime[i] << " ";
cout << endl;
return 0;
}
i % prime[j] == 0表示 i 之前被 prime[j] 筛过了。
由于 prime 里面质数是从小到大的,所以 i 乘上其他的质数的结果一定也是prime[j] 的倍数,它们都被筛过了,不需要再筛。