质数筛算法详解
在信息竞赛中,我们总是会遇到很多判断质数的题目,那么在这里就由我来给大家讲解一下质数筛算法(这里所有讲的算法都是基于筛出从
1.普通筛法
最普通的筛法,也就是将前
关键代码
for(int i=1;i<=n;++i)//枚举1到n
{
bool flg=0;
for(int j=2;j<i;++j)//枚举2到i
{
if(i%j==0)//如果i%j=0,也就是i已经不为素数了
{
flg=1;//打上标记
break;//跳出循环,不用再枚举了
}
}
if(flg==0)//如果没有被打上标记
prime[i]=1;//prime来标记这个数是否为素数。
}
这样的时间复杂度最劣近似
2.普通筛法的优化
学过奥数的朋友们可能会发现,在判断素数的时候,不一定需要枚举到
关键代码
for(int i=1;i<=n;++i)//枚举1到n
{
bool flg=0;
for(int j=2;j*j<=i;++j)//枚举2到i
{
if(i%j==0)//如果i%j=0,也就是i已经不为素数了
{
flg=1;//打上标记
break;//跳出循环,不用再枚举了
}
}
if(flg==0)//如果没有被打上标记
prime[i]=1;//prime来标记这个数是否为素数。
}
这样的时间复杂度最劣近似
3.暴力筛
我们发现,上面两种筛法会筛到许多没有意义的数,所以我们必须换一种思想方式。
暴力筛,就是先将
仍然是要从
如果
最终筛完之后,如果
关键代码
memset(prime,1,sizeof(prime));
priem[1]=0;
for(int i=2;i<=n;++i)
{
if(prime[i])
{
for(int j=2;j*i<=n;++j)
prime[i*j]=0;
}
}
显然,该程序一共会执行
4.埃氏筛
埃氏筛是基于暴力筛法的一种优化。
我们发现,对于暴力筛中小于
memset(prime,1,sizeof(prime));
priem[1]=0;
for(int i=2;i<=n;++i)
{
if(prime[i])
{
for(int j=i;j*i<=n;++j)
prime[i*j]=0;
}
}
对于第一重循环,可以只枚举到
对于时间复杂度,因蒟蒻能力有限,不会证明,只给出具体时间复杂度是
5.欧拉筛(线性筛)
我们发现,埃氏筛已经很快了,但是还是有所不足。
因为在埃氏筛中,有很多数有可能被筛到很多次(例如
首先,我们定义
如果当前已经枚举到了
然后我们每一次枚举都要做这个循环: 枚举
注意,接下来是重点! 如果
为什么呢,我们可以这样想。
我们假设当前枚举到的
则在枚举
当枚举到了
最后枚举
关键代码
memset(st,0,sizeof(st));
st[1]=0;
for(i=2;i<=n;i++)
{
if(st[i])
primes[cnt++]=i;
for(j=0;primes[j]*i<=n&&j<=cnt;j++)
{
st[primes[j]*i]=0;
if(i%primes[j]==0)
break;
}
}
关于正确性
你可能会问,为啥他一定能把所有的素数筛到?
假设有质数没有筛到,其中一个为
设其最小质因子为
则当我们枚举到
假设使他
而这样的话,
所以这样的方法一定是正确的,且一定使用到的最小质因子来筛。
这样的时间复杂度为
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!