埃氏筛(求素数)

介绍了一种简单易懂的素数筛选方法——埃氏筛法。此算法的时间复杂度为O(nloglogn),通过将已知素数的倍数标记为合数来寻找素数。虽然效率受重复标记的影响,但在实际应用中仍被广泛采用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

埃氏筛(求素数)

众多筛法中最简单且容易理解的一种,时间复杂度为O(nloglogn)(∑1nni\sum_1^n\frac{n}{i}1nin),在找到一个素数后,马上将所求范围内该素数的倍数标记为合数。埃氏筛法存在的问题是会对同一合数进行多次标记,从而影响效率。

const int maxn = 101;   // 表长
int prime[maxn], pNum = 0;  // prime存放素数,pNum为素数个数
bool p[maxn] = {false};     // 标记,素数false,合数true

void eratosthenesSieve(int n)
{
    for (int i = 2; i <= n; i++)
    {
        if (p[i] == false)      // 如果i是素数
        {
            prime[pNum++] = i;  // 记录i
            for (int j = i + i; j <= n; j += i)     // 筛去所有i的倍数
                p[j] = true;
        }
    }
}

<think>好的,我需要解决用户关于埃氏筛法素数的例题和代码实现的请。首先,我得回忆一下埃氏筛法的基本原理,确保自己理解正确。埃氏筛法是通过标记合数来筛选素数,从2开始,将每个素数的倍数都标记为非素数,这样剩下的就是素数了。用户提到了几个引用内容,里面包含不同的代码示例和区间筛法的说明。我需要参考这些内容,但用户真正需要的是例题或代码实现。因此,我应该先给出一个标准的埃氏筛法代码,可能结合引用中的例子,比如引用[1]和[2]中的代码,但要注意用户可能希望看到的是C++或Java的实现,不过用户提供的示例中有Python的快速排序,所以可能也需要Python的代码?不过根据引用中的代码,C++和Java的示例较多,用户的问题可能偏向于算法实现,所以应该选择常见的语言,比如C++或Python。接下来,我需要确保代码正确,符合埃氏筛法的逻辑。例如,初始化标记数组,将0和1标记为非素数,然后从2开始循环,如果当前数未被标记,则将其倍数全部标记为合数。引用[1]和[2]中的代码都是这样的结构,需要注意循环的起始点和步长是否正确。 然后,用户可能需要例题,比如如何用埃氏筛法解某个范围内的素数,或者处理大区间的筛法(如引用[4]中的区间筛)。这里可能需要给出一个具体的例子,比如n以内的素数,或者解决某个问题,比如统计素数的数量,或者输出所有素数。另外,用户可能希望看到代码的解释,说明每一步的作用,这样他们可以更好地理解。例如,初始化数组,标记0和1,然后遍历每个数,如果是素数就标记其倍数。同时,时间复杂度的解释,埃氏筛法的时间复杂度是O(n loglog n),这可以作为补充说明。还需要注意用户提到的LaTeX格式要,所有行内数学表达式要用$...$,比如时间复杂度写成$O(n\log\logn)$,而独立公式用$$...$$。例如,在解释算法复杂度时可能需要用到。可能还需要考虑例题的应用场景,比如解决LeetCode上的某个问题,例如LeetCode204题“计数素数”,这正是埃氏筛法的典型应用。可以给出这个例题的解决方案,结合代码实现,这样用户可以看到实际应用。另外,引用[4]提到的区间筛法可能是一个扩展内容,如果用户的问题涉及到大区间的素数筛选,可以简要提及,并提供相应的例题或代码。例如,区间[L,R]内的素数,其中R很大,但区间长度较小的情况,这时候可以使用区间筛法,先筛出√R以内的素数,再用这些素数去筛区间内的合数。最后,生成相关问题需要考虑用户可能进一步的问题,比如埃氏筛法的优化(如引用中的代码是否有优化空间),时间复杂度分析,与其他筛法的比较(如欧拉筛),或者错误处理(如输入范围过大时的内存问题)等。</think>### 埃氏筛法素数详解 #### 一、算法原理 埃氏筛法通过标记合数实现素数筛选。步骤如下: 1. 初始化标记数组`a[]`,默认所有数都是素数(`false`) 2. 将0和1标记为非素数(`true`) 3. 从2开始遍历,若当前数未被标记为合数,则将其所有倍数标记为合数 数学依据:任意合数$n$必有小于等于$\sqrt{n}$的质因数[^4] #### 二、标准代码实现(C++) ```cpp #include <iostream> #include <cstring> using namespace std; const int N = 1e7 + 5; // 根据问题规模调整 bool a[N]; // false表示素数 void eratosthenes(int n) { memset(a, 0, sizeof(a)); a[0] = a[1] = true; // 标记非素数 for(int i = 2; i*i <= n; i++) { // 优化:只需遍历到√n if(!a[i]) { for(int j = i*i; j <= n; j += i) // 从i²开始标记 a[j] = true; } } } ``` **时间复杂度**:$O(n \log \log n)$[^1] #### 三、典型例题 **LeetCode 204. 计数素数** 题目:统计所有小于非负整数n的质数的数量 解法: ```cpp class Solution { public: int countPrimes(int n) { if(n <= 2) return 0; vector<bool> isPrime(n, true); isPrime[0] = isPrime[1] = false; for(int i = 2; i*i < n; i++) { if(isPrime[i]) { for(int j = i*i; j < n; j += i) isPrime[j] = false; } } return count(isPrime.begin(), isPrime.end(), true); } }; ``` #### 四、区间筛法(处理超大范围) **例题**:区间$[L, R]$内的素数,其中$1 \leq L \leq R \leq 10^{12}$且$R-L \leq 10^6$ ```cpp void interval_sieve(long long L, long long R) { vector<bool> isPrime(R-L+1, true); if(L == 0) isPrime[0] = false; if(L <= 1) isPrime[1-L] = false; // 先用普通筛法得到√R内的素数 int max_p = sqrt(R); vector<bool> sieve(max_p+1, true); for(int p=2; p<=max_p; p++){ if(sieve[p]){ for(long long j=max(2LL*p, (L+p-1)/p*p); j<=R; j+=p) isPrime[j-L] = false; for(int j=p*p; j<=max_p; j+=p) sieve[j] = false; } } // 输出结果 for(long long i=L; i<=R; i++) if(isPrime[i-L]) cout << i << endl; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值