C++ 中的 **普通筛、埃氏筛、线性筛**,它们都是求质数或判断质数的方法

普通筛、埃氏筛、线性筛,它们都是求质数或判断质数的方法,但原理和复杂度不同。

1️⃣ 普通筛(暴力判断质数)

思路:

  • 对每个数 i(2 ≤ i ≤ n),判断它是否能被小于它的数整除。
  • 如果不能整除,则 i 是质数。

复杂度:

  • 最坏情况下 O(n√n),当 n 较大时效率低。

C++ 示例:

#include <bits/stdc++.h>
using namespace std;

bool isPrime(int x) {
    if (x < 2) return false;
    for (int i = 2; i * i <= x; ++i)
        if (x % i == 0) return false;
    return true;
}

int main() {
    int n;
    cin >> n;
    for (int i = 2; i <= n; ++i) {
        if (isPrime(i)) cout << i << " ";
    }
    return 0;
}

2️⃣ 埃氏筛(Sieve of Eratosthenes)

思路:

  1. 建立长度为 n 的布尔数组 is_prime,初始都为 true。
  2. 从 2 开始,若 i 是质数,则把 i 的所有倍数标记为非质数。
  3. 最终 is_prime[i] 为 true 的就是质数。

复杂度:

  • O(n log log n)
  • 对 n ≤ 10⁷ 或 10⁸ 都够用。

C++ 示例:

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<bool> is_prime(n+1, true);
    is_prime[0] = is_prime[1] = false;

    for (int i = 2; i*i <= n; ++i) {
        if (is_prime[i]) {
            for (int j = i*i; j <= n; j += i)
                is_prime[j] = false;
        }
    }

    for (int i = 2; i <= n; ++i) {
        if (is_prime[i]) cout << i << " ";
    }

    return 0;
}

3️⃣ 线性筛(Linear Sieve / 欧拉筛)

特点:

  • 保证每个合数只被它最小的质因子标记一次。
  • 可以顺序生成质数数组 primes
  • 复杂度 O(n)(比埃氏筛更快)。

思路:

  1. 遍历每个数 i(2 ≤ i ≤ n)

  2. 如果 i 是质数,加入 primes 数组

  3. 遍历 primes 数组:

    • 计算 i * primes[j] ≤ n
    • 标记 i * primes[j] 为非质数
    • 如果 i % primes[j] == 0,则 break(保证每个数只被它最小的质因子标记一次)

C++ 示例:

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> primes;
    vector<bool> is_prime(n+1, true);

    for (int i = 2; i <= n; ++i) {
        if (is_prime[i]) primes.push_back(i);
        for (int p : primes) {
            if (i * p > n) break;
            is_prime[i*p] = false;
            if (i % p == 0) break;
        }
    }

    for (int p : primes) cout << p << " ";
    return 0;
}

特点对比:

筛法 时间复杂度 优点 缺点
普通筛 O(n√n) 代码简单 n 大时慢
埃氏筛 O(n log log n) 高效,易实现 不能直接获取最小质因子
线性筛 O(n) 高效,可求最小质因子 实现稍复杂

下面是一张“一图看懂”三种筛法的对比演示。

n = 30 时的筛法遍历轨迹(✅ 保留,❌ 划掉)

下标: 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
--------------------------------------------------------------------------------------------------------------------
普通筛
  i=2 ✅ → 把 4 6 8 10 12 14 16 18 20 22 24 26 28 30 全划 ❌
  i=3 ✅ → 把 6 9 12 15 18 21 24 27 30 全划 ❌(6/12/18/24/30 被重复划)
  i=4 已 ❌
  i=5 ✅ → 把 10 15 20 25 30 全划 ❌(又重复)
  ……
  每个合数会被它所有质因子各划一次 → 多次标记

--------------------------------------------------------------------------------------------------------------------
埃氏筛
  i=2 ✅ → 从 2²=4 开始,步长 2:4 6 8 10 12 14 16 18 20 22 24 26 28 30 ❌
  i=3 ✅ → 从 3²=9 开始,步长 3:9 12 15 18 21 24 27 30 ❌(12/18/24/30 虽重复,但起点高,总量减半)
  i=4 已 ❌
  i=5 ✅ → 从 5²=25 开始,步长 5:25 30 ❌
  ……
  每个合数只被它的「最大质因子」划一次 → 仍可能重复,但少很多

--------------------------------------------------------------------------------------------------------------------
线性筛(欧拉筛)
  外层 i 从 2→30
  i=2 ✅ → 划 2×2=4 ❌
  i=3 ✅ → 划 3×2=6 ❌, 3×3=9 ❌
  i=4 ❌ → 划 4×2=8 ❌(4%2==0 立即 break,不再划 4×3=12)
  i=5 ✅ → 划 5×2=10 ❌, 5×3=15 ❌, 5×5=25 ❌
  i=6 ❌ → 划 6×2=12 ❌(6%2==0 break,不再划 6×3=18)
  ……
每个合数只被它最小的质因子标记一次。

--------------------------------------------------------------------------------------------------------------------
结果(30 以内质数)
✅ 保留:2 3 5 7 11 13 17 19 23 29
π(30) = 10

把上图转成记忆口诀
普通筛:见质数就狂划所有倍,重复无妨。
埃氏筛:从平方开始划,省一半。
线性筛:一遇整除就刹车,每个合数只被最小质因子划一次,真正线性。

⚠️备注:
下面把你提供的内容进一步整理成 更简洁、严谨、适合讲解或考试使用的版本,方便你在课上或材料中使用。


✅ 最大质因子(Greatest Prime Factor, GPF)

定义:
一个正整数的所有质因子(prime factors)中 最大的那个质数,称为它的最大质因子。

注意:

  • 质因子只看质数。
  • 重复因子不影响最大值(比如 12 的 2 出现两次也不影响答案)。

例 1:12

分解:
[
12 = 2 \times 2 \times 3
]
质因子集合 = {2, 3}
最大质因子 = 3

例 2:100

[
100 = 2 \times 2 \times 5 \times 5
]
质因子集合 = {2, 5}
最大质因子 = 5


✅ 最小质因数(Smallest Prime Factor, SPF)

定义:
一个正整数的所有质因子中 最小的那个质数,称为它的最小质因数。

例 1:12

质因子集合 = {2, 3}
最小质因数 = 2

例 2:100

质因子集合 = {2, 5}
最小质因数 = 2


🔍 二者对比总结

概念 含义 示例(n=100)
最大质因子 所有质因子中最大的质数 5
最小质因数 所有质因子中最小的质数 2
  • 最大质因子 = 分解中出现的最大质数
  • 最小质因数 = 分解中出现的最小质数

posted @ 2025-11-16 18:07  kkman2000  阅读(13)  评论(0)    收藏  举报