欧拉筛和埃氏筛求质因子个数

埃氏筛法简单易懂直接上代码

void solve()
{
   
   
    for(int i=2;i<=20000000;i++)
        if(!test[i])
            
欧拉法(线性埃氏筛法(拉托斯特尼法)都是用于**高效选出小于等于某个整数 n 的所有素数**的算法。它们在时间复杂度、实现方式适用场景上有显著区别。 下面我将详细解释两者的原理、C++ 实现,并对比其优劣。 --- ## ✅ 1. 拉托斯特尼法(Sieve of Eratosthenes,简称“埃氏筛”) ### 🔍 原理: - 从最小的质数 2 开始,把它的所有倍数(除了自己)标记为合数。 - 然后找下一个未被标记的数,它一定是质数,再将其所有倍数标记为合数。 - 重复此过程直到遍历到 √n。 > ❗ 注意:一个合数可能被多个质因数重复标记(如 12 被 2 3 都标记过),这是效率损失的原因。 ### ⏱ 时间复杂度:O(n log log n) ### ✅ 空间复杂度:O(n) ### 📌 C++ 实现: ```cpp #include <iostream> #include <vector> using namespace std; vector<int> sieve_of_eratosthenes(int n) { vector<bool> is_prime(n + 1, true); vector<int> primes; is_prime[0] = is_prime[1] = false; for (int i = 2; i * i <= n; i++) { if (is_prime[i]) { // 标记 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]) { primes.push_back(i); } } return primes; } int main() { int n = 30; vector<int> primes = sieve_of_eratosthenes(n); cout << "Primes up to " << n << ": "; for (int p : primes) { cout << p << " "; } cout << endl; return 0; } ``` --- ## ✅ 2. 欧拉法(Euler's Sieve,又称线性) ### 🔍 原理: - 维护一个 `primes` 数组记录已知质数。 - 对每个数 i(从 2 到 n),用已知质数去掉 `i × primes[j]`。 - **关键优化**:一旦 `primes[j]` 整除 `i`,就停止后续除 —— 这保证了每个合数只被它的**最小质因数**一次。 > ✅ 因此,每个合数仅被标记一次 → 时间复杂度 O(n) ### ⏱ 时间复杂度:O(n)(线性) ### ✅ 空间复杂度:O(n) ### 📌 C++ 实现: ```cpp #include <iostream> #include <vector> using namespace std; vector<int> euler_sieve(int n) { vector<bool> is_prime(n + 1, true); vector<int> primes; is_prime[0] = is_prime[1] = false; for (int i = 2; i <= n; i++) { if (is_prime[i]) { primes.push_back(i); } // 用已知质数去合数 for (int j = 0; j < primes.size() && i * primes[j] <= n; j++) { is_prime[i * primes[j]] = false; if (i % primes[j] == 0) { break; // 关键:primes[j] 是 i 的最小质因数 } } } return primes; } int main() { int n = 30; vector<int> primes = euler_sieve(n); cout << "Primes up to " << n << ": "; for (int p : primes) { cout << p << " "; } cout << endl; return 0; } ``` --- ## 🔁 两种法的核心区别 | 特性 | 埃氏筛 | 欧拉 | |------|--------|--------| | 时间复杂度 | O(n log log n) | O(n)(线性) | | 是否重复标记 | 是(如 12 被 2 3 都) | 否(每个合数只被最小质因数) | | 实现难度 | 简单直观 | 稍复杂,需理解 `i % primes[j] == 0` 的意义 | | 的过程中是否收集质数 | 可以 | 必须收集 | | 适合学习阶段 | 初学者 | 中级/进阶 | | 扩展性(如最小质因数、φ 函数等) | 差 | 强 | --- ## 💡 为什么 `i % primes[j] == 0` 就要 break? 假设 `i` 能被 `primes[j]` 整除,说明 `primes[j]` 是 `i` 的一个质因数。 那么对于下一个质数 `primes[j+1] > primes[j]`,考虑 `i * primes[j+1]`: - 它的最小质因数其实是 `primes[j]`(因为 `i` 包含 `primes[j]`) - 所以应该由 `primes[j]` 来掉它,而不是现在就 👉 提前 break 可避免重复,确保线性复杂度。 --- ## ✅ 示例输出(n=30): ``` Primes up to 30: 2 3 5 7 11 13 17 19 23 29 ``` 两者输出一致,但欧拉更快更高效。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值