参考视频:
找素数的3种方法 试除法 埃氏筛 线性筛 动画演示过程 noi大纲数论基础_哔哩哔哩_bilibili
题目:
试除法:
埃氏筛:
核心思想:素数的整数倍一定是合数 找出合数剩下的就是素数
void sieve_of_eratosthenes(int m, int n) {
int is_prime[n + 1]; // 标记数组,1 表示素数,0 表示非素数
memset(is_prime, 1, sizeof(is_prime)); // 初始化为 1(假设全是素数)
is_prime[0] = is_prime[1] = 0; // 0 和 1 不是素数
for (int i = 2; i * i <= n; i++) {
if (is_prime[i]) {
for (int j = i * i; j <= n; j += i) {//从i*i开始
is_prime[j] = 0; // 标记为非素数
}
}
}
// 输出从 m 到 n 的素数
for (int i = m; i <= n; i++) {
if (is_prime[i]) {
printf("%d ", i);
}
}
printf("\n");
}
int main() {
int m, n;
printf("输入范围 m 和 n(m <= n):");
scanf("%d %d", &m, &n);
sieve_of_eratosthenes(m, n);
return 0;
}
找出从m到n之间的素数就是先找出从1到n的所有素数 但是只把从m到n的素数输出
欧拉筛:
void euler_sieve(int m, int n) {
int is_prime[n + 1]; // 标记数组,1 表示素数,0 表示非素数
int primes[n + 1]; // 用于存储所有素数
int prime_count = 0; // 素数计数
memset(is_prime, 1, sizeof(is_prime)); // 初始化为 1(假设全是素数)
is_prime[0] = is_prime[1] = 0; // 0 和 1 不是素数
for (int i = 2; i <= n; i++) {
if (is_prime[i]) {
primes[prime_count++] = i; // 保存素数
}
for (int j = 0; j < prime_count && i * primes[j] <= n; j++) {
is_prime[i * primes[j]] = 0; // 标记非素数
if (i % primes[j] == 0) {
break; // 保证每个数只被其最小的质因数筛除
}
}
}
// 输出从 m 到 n 的素数
for (int i = 0; i < prime_count; i++) {
if (primes[i] >= m) {
printf("%d ", primes[i]);
}
}
printf("\n");
}
int main() {
int m, n;
printf("输入范围 m 和 n(m <= n):");
scanf("%d %d", &m, &n);
euler_sieve(m, n);
return 0;
}
对比埃氏筛和欧拉筛:
1. 埃式筛法:
- 简单直观,适合初学者。
- 时间复杂度约为 (O(nloglog n))。
- 会多次标记同一个数的倍数。
实现简单 适用于范围更小的情况。
2. 欧拉筛法:
- 更高效,保证每个数只被其最小素因子标记一次。
- 时间复杂度为 (O(n))。
- 实现略复杂,但对大范围筛选更有优势。
效率更高 适用于范围更大的情况。