介绍
欧拉筛法(Euler’s Sieve),又称为线性筛法,是一种高效的素数筛选算法,其时间复杂度和空间复杂度都是线性的,可以在O(n)的时间和空间内完成筛选。欧拉筛法有效地避免了埃拉托斯特尼(Eratosthenes)筛法中重复的筛选,保证了每个数只被筛选一次,从而提高了筛选效率。
基本思想
欧拉筛法的基本思想是基于每个合数必然有其最小质因子,且每个合数只被其最小质因子筛选一次。算法从2开始,逐步枚举每个数,对于每个未被筛选的数,视为素数,并用它来筛选其后的数。在筛选过程中,如果一个数能被之前的某个素数整除,则停止用该素数及之后的素数进行筛选,因为该数已经被其最小质因子筛选过。
算法过程
- 初始化:将所有数标记为素数(或未筛选状态),通常使用一个数组来记录每个数的状态。
- 枚举:从2开始,逐个枚举每个数i。如果i未被筛选(即i是素数),则将其加入素数列表,并用i来筛选后续的数。否则,跳过i,继续枚举下一个数。
- 筛选:对于每个素数p(已加入素数列表),用p乘以i来筛选i的倍数。但需要注意,当i能被p整除时(即i是p的倍数),停止用p及之后的素数来筛选i的倍数,因为此时i的倍数已经被其更小的质因子筛选过。
- 重复:重复上述过程,直到枚举完所有数。
优点
- 线性时间复杂度:欧拉筛法的时间复杂度为O(n),适合处理大数据量的素数筛选问题。
- 不重复筛选:通过确保每个合数只被其最小质因子筛选一次,避免了重复筛选,提高了效率。
应用
欧拉筛法不仅用于筛选素数,还可以用于求解其他与素数相关的数论问题,如求1n之间所有自然数的欧拉函数φ(x)、求1n之间每个数的因子个数和因数和等。
示例代码(C++)
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
const int MAXN = 1000000; // 定义最大范围
int prime[MAXN], is_prime[MAXN], cnt = 0; // prime用于存储素数,is_prime用于标记素数(0为素数,1为合数),cnt记录素数个数
void euler_sieve(int n) {
for (int i = 2; i <= n; i++) {
if (!is_prime[i]) {
prime[cnt++] = i; // i是素数,加入素数列表
}
for (int j = 0; j < cnt && i * prime[j] <= n; j++) {
is_prime[i * prime[j]] = 1; // 标记i*prime[j]为合数
if (i % prime[j] == 0) break; // 如果i能被prime[j]整除,则停止筛选
}
}
}
int main() {
int n;
cout << "请输入一个正整数N:" << endl;
cin >> n;
euler_sieve(n);
cout << "N内的所有素数及个数如下:" << endl;
for (int i = 0; i < cnt; i++) {
cout << prime[i] << endl;
}
cout << "共有" << cnt << "个素数" << endl;
return 0;
}