一、埃氏筛法(Sieve of Eratosthenes):
主要思想是从2开始将所有数的倍数都筛去。
#include <iostream>
#include <vector>
using namespace std;
vector<int> sieveOfEratosthenes(int n) {
vector<bool> prime(n + 1, true);
prime[0] = prime[1] = false;
for (int i = 2; i * i <= n; i++) {
if (prime[i]) {
for (int j = i * i; j <= n; j += i) {
prime[j] = false;
}
}
}
vector<int> primes;
for (int i = 2; i <= n; i++) {
if (prime[i]) {
primes.push_back(i);
}
}
return primes;
}
int main() {
int n = 100; // 这里可以修改范围,例如要找100以内的质数
vector<int> result = sieveOfEratosthenes(n);
for (int prime : result) {
cout << prime << " ";
}
cout << endl;
return 0;
}
主要分为3步:
- 初始化:创建一个布尔类型的
vector
prime
,长度为n + 1
,并初始化为true
,表示假设所有数都是质数,并初始化0和1为false
。 - 筛掉所有偶数:然后从2开始,对于每个质数
i
,将其倍数(从i * i
开始,因为小于i * i
的倍数已经被更小的质数标记过了)标记为false
。 - 取出指定范围内的素数:最后遍历
prime
数组,将值为true
的索引(即质数)添加到结果vector
中,并在main
函数中输出这些质数。
二、欧拉筛(线性筛):
#include <iostream>
#include <vector>
using namespace std;
vector<int> eulerSieve(int n) {
vector<bool> isPrime(n + 1, true);
vector<int> primes;
for (int i = 2; i <= n; i++) {
if (isPrime[i]) {
primes.push_back(i);
}
for (int j = 0; j < primes.size() && i * primes[j] <= n; j++) {
isPrime[i * primes[j]] = false;
if (i % primes[j] == 0) {
break;
}
}
}
return primes;
}
int main() {
int n = 100; // 这里可以修改n的值来获取不同范围内的素数
vector<int> primeNumbers = eulerSieve(n);
for (int prime : primeNumbers) {
cout << prime << " ";
}
cout << endl;
return 0;
}
在这段代码中:
- 初始化:创建一个布尔类型的数组
isPrime
,初始时都设为true
,表示所有数都可能是素数。同时创建一个向量primes
用于存储找到的素数。 - 保存素数:外层循环从
2
到n
遍历每个数i
。如果i
是素数(isPrime[i]
为true
),就将其加入到primes
向量中。 - 筛去合数:内层循环遍历已找到的素数
primes[j]
,将i * primes[j]
标记为非素数(isPrime[i * primes[j]] = false
)。当i
能被primes[j]
整除时就停止内层循环,这样可以保证每个合数只被其最小质因数筛一次,从而实现线性时间复杂度。