欧拉筛——找出 [2, n] 区间内的所有素数

 欧拉筛:

        欧拉筛(线性筛)是一种用于高效找出n范围内所有素数的算法,时间复杂度为 O(n),其核心优势在于避免了对同一个合数的重复标记。

算法原理

欧拉筛的核心思路是让每个合数只被它的最小质因数筛去

简单的讲就是找出当前未找出的最小素数,然后顺便把所有以该素数为最小质因数的数剔除掉

为了避免重复剔除同一个数所导致的时间浪费,所有我们规定一个剔除原理,即让每个合数只被它的最小质因数筛去。这里是为了避免比如5 * 7 =35这种情况,35只被5剔除,不被7重复剔除。

欧拉筛是线性的,从小到大的。

欧拉筛一定会遍历每一个数(单是把素数收录就需求遍历)。

欧拉筛可以分为两步

  1. 对当前数 i 的素性判断,决定是否收录。
  2. 对未被遍历的数进行剔除。
vector<int> eulerSieve(int n) {
    vector<bool> is_prime(n + 1, true);// 初始化标记都是素数
    is_prime[0] = is_prime[1] = false;// 0 和 1 不是素数
    vector<int> primes;
    for (int i = 2; i <= n; ++i) {
        if (is_prime[i]) {
            primes.push_back(i);// 如果 i 是素数,将其加入 primes 向量
        }
        // 遍历已找到的素数,进行剔除
        for (int j = 0; j < primes.size() && i * primes[j] <= n; ++j) {
            is_prime[i * primes[j]] = false;// 标记 i * primes[j] 为合数
            if (i % primes[j] == 0) {// 当 i 能被 primes[j] 整除时,停止遍历
                break;
            }
        }
    }
    return primes;
}

如果i%prime[ j ]=0则i是某个已经确定的素数prime[ j ]的倍数,则i*prime[ j ]应该由prime[ j ]来去除.

for (int j = 0; j < primes.size() && i * primes[j] <= n; ++j) {
    is_prime[i * primes[j]] = false;// 标记 i * primes[j] 为合数
    if (i % primes[j] == 0) {// 当 i 能被 primes[j] 整除时,停止遍历
        break;
    }
}

这里我们需要关注的主体并不是primes【j】而是 ,因为这个循环的目的是去除每个素数的i倍,所以去除了i*primes【j】之后应当停止,因为primes【j】后面每个素数 * i都是在给以primes【j】为最小质因数的数剔除。

i*prime(next)=k* prime(now)*prime(next),这是一个以prime(now)为最小质因数的合数,而不是prime(next)为最小质因数的合数。所以我们直接break,此后的所有prime(next)都没有必要再乘i了。后面的素数都被primes[j]给筛了

posted @ 2025-11-16 16:18  mc12356  阅读(27)  评论(0)    收藏  举报  来源