详细动图展示欧拉筛法的原理

本文详细解析欧拉筛法的工作原理,通过C++代码实例演示其高效之处,对比埃氏筛法,探讨空间与时间的权衡。

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

 欧拉筛法是比埃氏筛法更高效的一种素数筛法,确保每个合数只被筛掉一次,算法复杂度达到O(n),被称为线性筛。

为了更好地理解它的原理,我制作了一个动态展示,配合源代码一起阅读,相信您能很快理解欧拉筛法的妙处。

#include<iostream>
#define MAX 100000001
using namespace std;
bool a[MAX];
int prime[MAX];
int main(){
	int n, p=0;
	cin >> n;
	for (int i=2; i*i<=n; i++) {
		if (a[i]==0) {
			prime[p++]=i;
		}
		for (int j=0; j<h && i*prime[j]<=n; j++){
			a[j]= 1;
			// 非常关键的停止点 
			if(i%prime[j]==0) break; 
		}
	}
	for (int i=2; i<=n; i++){
		if (a[i]==0) {
			cout << i << " ";
		}
	}
	return 0;
}

当然,时间的提升,也必须付出一点点空间的代价。埃氏筛法可以在一个数组内进行标记,而欧拉筛法则必须使用两个数组,其中一个记录所有素数。

### 埃拉托斯特尼筛法 埃拉托斯特尼筛法(Sieve of Eratosthenes)是一种经典的用于找出不超过给定整数n的所有素数的方法。此方法的基本思路是从2开始,将每个素数的倍数标记为合数,直到遍历至根号下n为止。 对于每一个找到的素数p,在范围\[2, n\]内将其所有的倍数\(kp\)(k ≥ 2)都标记成非素数。当处理完毕后,未被标记过的数字即为素数[^4]。 #### 时间复杂度分析 该算法的时间复杂度大约为O(n log log n),这是因为对于每个素数都要执行多次删除操作,随着数值增大,待移除的数量逐渐减少。空间复杂度则主要取决于存储布尔数组的空间需求,通常情况下是线性的O(n)。 ```cpp // C++ implementation of Sieve of Eratosthenes to find all primes up to a given number 'n' #include <vector> using namespace std; void sieveOfEratosthenes(int n) { vector<bool> isPrime(n + 1, true); for (int p = 2; p * p <= n; ++p) { if (isPrime[p]) { // If not marked as composite yet. for (int i = p * p; i <= n; i += p) isPrime[i] = false; } } // Print all prime numbers less than or equal to n. for (int p = 2; p <= n; ++p) if (isPrime[p]) cout << p << " "; } ``` ### 欧拉筛法 欧拉筛法(Euler's Sieve),也被称为线性,是在埃氏的基础上进行了优化的一种更高效的寻找素数的方式。它通过记录已经发现的小于当前正在考虑的数m的所有素数列表,并利用这些已知素数去尝试去除更大的复合数,从而避免了重复劳并提高了效率[^1]。 核心在于维护一个素数表`primes[]`用来保存已经被确认下来的素数序列;每当遇到一个新的素数时就加入这个表格里。接着用新得到的素数乘以之前所有小于等于它的素数来进行选工作——如果某次相乘的结果超过了上限,则停止继续尝试更大值的操作。特别之处还体现在即使某个数已被其他较小素数所覆盖过也不会再次对其进行更新,这样就能确保整个过程中任何大于1且不是素数的自然数仅会被访问一次[^3]。 #### 时间复杂度分析 由于每个合数只会在其最小质因数处被唯一地标记一次,所以整体时间复杂度降为了严格的线性级别O(n)。 ```cpp // Implementation of Euler's Sieve in C++ #include <iostream> #include <vector> std::vector<int> euler_sieve(int limit){ std::vector<int> primes; bool visited[limit+1]; memset(visited,false,sizeof(bool)*(limit+1)); for(long long num=2;num<=limit;++num){ if(!visited[num]){ primes.push_back(num); } for(size_t idx=0;(idx<primes.size()) && ((long long)(num)*primes[idx]<=limit);++idx){ visited[(long long)(num)*primes[idx]]=true; if(num%primes[idx]==0)// Ensure each composite gets crossed off only once by its smallest prime factor break; } } return primes; } int main(){ int max_num = 50; auto result=euler_sieve(max_num); std::cout<<"Primes within "<<max_num<<":"; for(auto& val:result){ std::cout<<val<<' '; } return 0; } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

圣手书生肖让

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值