素数筛法(sieve of primer number)

洛谷:3383
OJ平台:P4272 P1194 P1151

方法一:埃氏筛法(sieve of Eratosthenes)

埃拉托斯特尼筛法,简称埃氏筛或爱氏筛,是一种由希腊数学家埃拉托斯特尼所提出的一种简单检定素数的算法。要得到自然数n以内的全部素数,必须把不大于根号n的所有素数的倍数剔除,剩下的就是素数。

isPrimer[]
isPrimer[]
index
index
0
0
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
13
13
14
14
15
15
~25
~25
~49
~49
data
data
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
i=2
i=2
0
0
0
0
0
0
0
0
1
1
0
0
1
1
0
0
1
1
0
0
1
1
0
0
1
1
0
0
1
1
0
0
0
0
0
0
i=3
i=3
0
0
0
0
0
0
0
0
1
1
0
0
1
1
0
0
1
1
1
1
1
1
0
0
1
1
0
0
1
1
1
1
0
0
0
0
i=4
i=4
i=4的时候,循环不进行,因为i=2的时候,已经把4标注成合数了。
i=4的时候,循环不进行,因为i=2的时候,已经把4标注成合数了。
i=5
i=5
0
0
0
0
0
0
0
0
1
1
0
0
1
1
0
0
1
1
1
1
1
1
0
0
1
1
0
0
1
1
1
1
1
1
0
0
i=6
i=6
i=6的时候,循环不进行,因为i=2的时候,已经把6标注成合数了。
i=6的时候,循环不进行,因为i=2的时候,已经把6标注成合数了。
i=7
i=7
1
1
0
0
0
0
0
0
0
0
1
1
0
0
1
1
0
0
1
1
1
1
1
1
0
0
1
1
0
0
1
1
1
1
1
1
 isPrimer[2] = 0;
for (long long i = 2; i <= m; i ++) {
if(!isPrimer[i])
for (long long j = i * i; j <= n; j += i)
isPrimer[j] = 1;
if(i * i > n)
break;
}
}
isPrimer[2] = 0;…
Text is not SVG – cannot display

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**************************************************************** 
 * 代码作者: Alex Li
 * 创建时间: 2023-06-21 12:35:06
 * 最后修改: 2025-03-01 10:41:52
 * 文件描述:  埃氏筛素数  O(nloglogn)
****************************************************************/

#include <iostream>
#include <cmath>
using namespace std;
 
const int maxn = 1000000;
bool isPrimer[maxn];    // i是合数isPrimer[i]为1,i是素数,isPrimer[i]为0
 
void sieve(long long n){
    int m = sqrt(n);
    isPrimer[2] = 0;
/*
从i*i开始筛选,小于i的数在之前的循环已经筛过,比如6是在i=2时候筛过了,所以j=3时就从3*3开始。
另外,由于i筛选的时候可能会重复前面已经筛过的,比如18,就是在i=2和3时,都筛一遍。
*/
    for (long long i = 2; i <= m; i++) {
        if (!isPrimer[i]){
            for (long long j = i * i; j <= n; j += i){
                isPrimer[j] = 1;
            }
        }
    }
}
 
int main(){
    long long n;
    cin >> n;
    sieve(n);
    for (long long i = 2; i < n; i++){
        if (isPrimer[i] == 0) cout << i << ' ';
    }
       
return 0;
}


方法二:线性筛法(linear sieve)

每个合数都 由它最小质因数剔除,剩下就是质数

index
index
0
0
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
13
13
14
14
15
15
~25
~25
visited
visited
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
prime[]
prime[]
2
2
0
0
0
0
0
0
0
0
1
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
i=3,Prime[1]
i=3,Prime[1]
2
2
3
3
0
0
0
0
0
0
0
0
1
1
0
0
1
1
0
0
0
0
1
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
i=4,Prime[]
i=4,Prime[]
2
2
3
3
visited[i*k]
visited[i*k]
0
0
0
0
0
0
0
0
1
1
0
0
1
1
0
0
1
1
1
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
i=5,Prime[2]
i=5,Prime[2]
2
2
3
3
5
5
visited[]
visited[]
0
0
0
0
0
0
0
0
1
1
0
0
1
1
0
0
1
1
1
1
1
1
0
0
1
1
0
0
0
0
1
1
1
1
i=2,Prime[0]
i=2,Prime[0]
visited[i*k]
visited[i*…
count=1
count=1
count=2
count=2
visited[i*k]
visited[i*…
count=3
count=3
for (int i =2; i <=n; i++){ //i从2开始找
//visited[i]如果=0,则说明i是质数,放到pirme[i]数组里,
     //count加1,visited[i]因为是全局数组,默认初始值是0 
if(!visited[i]) {
prime[count]=i;
count++;
}
//从最小的质数开始枚举
for (int j = 0; j<count&&prime[j]*i<=n; j++){
int k=prime[j];
visited[i*k]=1;//i乘以小于i的质数,标识出合数
//如果i是质数,当k=i时,退出
//如果i是合数,当k等于i最小质因子的时候退出。
if(i%k==0)break;
}
}
for (int i =2; i <=n; i++){ //i从2开始找…
Text is not SVG – cannot display

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**************************************************************** 
 * 代码作者: Alex Li
 * 创建时间: 2023-06-21 20:39:52
 * 最后修改: 2025-03-01 11:52:29
 * 文件描述: 线性筛素数  O(n)
****************************************************************/
// 线性筛法是从小到大筛选,但是每个数只会被最小质因子筛选一次。

#include <iostream>
#include <vector>
using namespace std;

const int MAXN = 100000001;
vector<bool> visited(MAXN, false); // 标识数组,visited[i] = true 说明 i 是合数
vector<int> prime; // 存储质数的数组

int main() {
    int n;
    cin >> n;

    for (int i = 2; i <= n; i++) {
        if (!visited[i]) {
            prime.push_back(i); // 如果 i 是质数,添加到 prime 数组中
        }
        // 从最小的质数开始枚举
        for (int j = 0; j < prime.size() && prime[j] * i <= n; j++) {
            int k = prime[j];
            visited[i * k] = true; // 标记合数
            // 如果 i 是质数,当 k = i 时,退出
            // 如果 i 是合数,当 k 等于 i 的最小质因子时退出
            if (i % k == 0) break;
        }
    }

    cout << prime.size(); // 输出质数的个数
    return 0;
}

洛谷:P3383

Scroll to Top