【模板】埃拉托色尼筛法(埃氏筛)

一、算法简介

在数论与编程竞赛中,求解 [1,n][1,n][1,n] 范围内的所有质数是常见的基础问题。埃拉托色尼筛法(Sieve of Eratosthenes) 是一种古老而高效的算法,可以在 O(nlog⁡log⁡n)O(n \log \log n)O(nloglogn) 的时间复杂度内完成这一任务。


二、基本思想

埃氏筛的核心思想是:

对于每一个从小到大的质数 ppp,将其所有的倍数(2p,3p,4p,…2p, 3p, 4p, \dots2p,3p,4p,)标记为合数。
最终,所有未被标记的数就是质数。

举例说明:
n=30n = 30n=30,初始认为 2∼302\sim 30230 都是质数。
我们从 222 开始,依次把 4,6,8,…4,6,8,\dots4,6,8, 标记为合数;
然后处理下一个未被标记的 333,再把 6,9,12,…6,9,12,\dots6,9,12, 标记为合数;
如此反复,直到 n\sqrt{n}n


三、代码实现

以下是使用 C++ 编写的埃氏筛标准模板

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

const int N = 1e5 + 10; // 设置一个足够大的常数N,表示数组大小

vector<bool> ans(N, true); // 初始化素数表,默认所有数都是素数(true)
vector<int> nums;          // 用于存储最终得到的所有质数

// 筛法主函数:获取1到n之间的所有素数
void get(int n)
{
    ans[0] = ans[1] = false; // 0 和 1 不是质数,直接标记为 false

    // 使用埃氏筛法,从 2 开始依次判断
    for (int i = 2; i <= n / i; i++)  // 等价于 i * i <= n
    {
        if (ans[i]) // 如果当前数 i 是质数(尚未被筛掉)
        {
            // 从 i*i 开始,而不是 2*i:
            // 因为 i < j < i*i 范围内的 i 倍数,如 2*i, 3*i 等,已被更小的质数筛掉了
            for (int j = i * i; j <= n; j += i) // 枚举 i 的所有倍数
            {
                ans[j] = false; // 将 j 标记为合数
            }
        }
    }

    // 将所有的质数加入 nums 数组
    for (int k = 2; k <= n; k++)
    {
        if (ans[k])
        {
            nums.push_back(k);
        }
    }
}

主函数调用如下:

int main()
{
    int n;
    cin >> n; // 输入要求筛到的最大范围

    get(n); // 执行筛法

    for (auto num : nums)
    {
        cout << num << " "; // 输出所有质数
    }

    return 0;
}

四、关键优化说明

1. 为什么从 i * i 开始筛?

因为在遍历到质数 iii 时,小于 iii 的质数已经处理了 2i,3i,...,(i−1)i2i, 3i, ..., (i-1)i2i,3i,...,(i1)i 的倍数。例如:

  • 6=2×36 = 2 \times 36=2×3 会在处理 222 时被筛掉;
  • 9=3×39 = 3 \times 39=3×3 会在处理 333 时被筛掉。

因此,从 i×ii \times ii×i 开始可以减少重复标记,提升效率。

2. 循环条件 i <= n / i

等价于 i * i <= n,这种写法可避免整数溢出,建议记住作为一种 防溢出技巧


五、时间与空间复杂度

  • 时间复杂度O(nlog⁡log⁡n)O(n \log \log n)O(nloglogn),非常高效
  • 空间复杂度O(n)O(n)O(n),主要用于布尔数组 ans[]

六、样例输入输出

输入:

100

输出:

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

七、适用场景与拓展

  • 快速判断一个数是否为质数(配合布尔数组)
  • 枚举某范围内的所有质数(如用于欧拉函数、积性函数计算)
  • 可拓展为线性筛(Euler 筛)以避免重复标记(时间复杂度为 O(n)O(n)O(n)

八、结语

埃拉托色尼筛法是数论的入门利器,是多种算法的基础工具。建议熟练掌握并牢记模板结构。同时要理解从 i * i 开始标记的数学依据,避免盲记公式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值