Eratosthenes筛法
Eratosthenes筛法
埃拉托斯特尼筛法,简称埃氏筛或爱氏筛,是一种由希腊数学家埃拉托斯特尼所提出的一种简单检定素数的算法。
用于求得[1, n]区间内的全部素数。
算法流程:
第一步,将[2, n]区间排成一列。
第二步:标出列表中的第一个数,筛去其所有的倍数。
不断重复第二步,被标记的就是[1, n]区间的所有素数。
例如:求[1,10]区间内的所有素数。
1.将[2, 10]排成一列
2.标出列表中的第一个数——2,筛去所有2的倍数
3.标出列表中的第一个数——3,筛去所有3的倍数
4.标出列表中的第一个数——5,筛去所有5的倍数
5.标出列表中的第一个数——7,筛去所有7的倍数
6.被标记的就是[1, 10]区间内的所有素数:2,3,5,7
从这个过程中我们可以看出,每次筛完后剩下的区间内第一个数一定是素数,因为合数一定是前面某一个素数的倍数,一定在前几次筛选的过程中被筛走了。
代码如下:
//若编译失败,请使用最高版本的Visual Studio
#include<iostream>
#include<vector>
using namespace std;
vector<int> sieve(int n)
{
vector<bool> a(n + 1, 1);
vector<int> b;
for (int i = 2; i <= n; i++)
for (int j = i + i; j <= n; j += i)
a[j] = false;
for (int i = 2; i <= n; i++)
if (a[i]) b.push_back(i);
return b;
}
优化
- 先把2的倍数筛掉,让i从3开始循环每次加2:
b.push_back(2);
for (int i = 3; i <= n; i += 2)
for (int j = i + i; j <= n; j += i)
a[j] = false;
for (int i = 2; i <= n; i++)
if (i % 2 != 0 && a[i]) b.push_back(i);
- 因为 i 2 i^2 i2之前的合数一定是某个小于i的素数的倍数,在前面的循环中已经被筛掉了,所以j可以直接从 i 2 i^2 i2开始循环。
for (int i = 3; i <= n; i += 2)
for (int j = i * i; j <= n; j += i)
a[j] = false;
- 由第二条优化的原理我们可以推断:i只需要循环到 n \sqrt n n就可以了。因为当i循环到 n \sqrt n n时,[1, i 2 i^2 i2]即[1, n]之间的所有合数已经被筛走了。
for (int i = 3; i <= (int)sqrt(n); i += 2)
for (int j = i * i; j <= n; j += i)
a[j] = false;
综上,代码为:
//若编译失败,请使用最高版本的Visual Studio
#include<iostream>
#include<vector>
using namespace std;
vector<int> sieve(int n)
{
vector<bool> a(n + 1, 1);
vector<int> b;
b.push_back(2);
for (int i = 3; i <= (int)sqrt(n); i += 2)
for (int j = i * i; j <= n; j += i)
a[j] = false;
for (int i = 2; i <= n; i++)
if (i % 2 != 0 && a[i])
b.push_back(i);
return b;
}