关于埃式筛法的极限优化

摘自https://blog.csdn.net/qq_43332305/article/details/82959066

关于素数的普通筛法想必大家都清楚。使用一个数组vis[n],从2遍历到n-1,每次碰到素数就把它的倍数剔除。这里有三种手段可以大大降低埃式筛法的时间复杂度:
先发埃式筛法模板,假设初始化vis所有成员为0,0代表是素数,1代表不是素数:

1 for(int i=2;i<=N;i++){
2         if(!vis[i]){
3             for(int j=2*i;j<=N;j+=i){
4                 vis[j]=1;
5             }
6         }
7     }

 


那么首先会想到一个问题,一个合数如果有因数,那么必定是成对存在,也就是筛子只用判断其中一个因数就可以了,比如15=3*5,在3的时候已经把15给筛掉了,何必去循环到5呢?于是优化如下,循环到根号n即可。

1 for(int i=2;i*i<=N;i++){//将i<=N换成i*i<=N
2         if(!vis[i]){
3             for(int j=2*i;j<=N;j+=i){
4                 vis[j]=1;
5             }
6         }
7     }

 


接下来是第二重优化。第二层循环中不是从j=2i开始,每次增加一个i,即剔除i的所有倍数吗?试想一下,6是不是被2筛过了,此时碰到素数3又要筛一遍。而j从2i到i*i,即2倍到i倍的变化,在第一层循环中,2~i-1已经把他们的素数倍数筛完,所以结论如下:
第i个数只用筛从 i 乘 i 开始到n的每个数,而不用从 2 乘 i 开始
接下来优化代码:

1 for(int i=2;i*i<=N;i++){//将i<=N换成i*i<=N
2         if(!vis[i]){
3             for(int j=i*i;j<=N;j+=i){//将2*i换成i*i
4                 vis[j]=1;
5             }
6         }
7     }

 

第三重优化是一个很小的改动与优化,在第二重循环中,每次增加素数的1倍,但除了2以外素数都是奇数,那么奇数乘以偶数是偶数,偶数情况早已被2筛完,故每次增加2i倍.

复制代码
1 for(int i=2;i*i<=N;i++){//将i<=N换成i*i<=N
2         if(!vis[i]){
3             int mul;//倍数
4             i==2?mul=1:mul=2;
5             for(int j=i*i;j<=N;j=j+i*mul){//将2*i换成i*i
6                 vis[j]=1;
7             }
8         }
9     }
复制代码

 

posted @   codeoos  阅读(942)  评论(0编辑  收藏  举报
编辑推荐:
· 继承的思维:从思维模式到架构设计的深度解析
· 如何在 .NET 中 使用 ANTLR4
· 后端思维之高并发处理方案
· 理解Rust引用及其生命周期标识(下)
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
阅读排行:
· Cursor预测程序员行业倒计时:CTO应做好50%裁员计划
· 当职场成战场:降职、阴谋与一场硬碰硬的抗争
· 用99元买的服务器搭一套CI/CD系统
· 35岁程序员的中年求职记:四次碰壁后的深度反思
· Excel百万数据如何快速导入?
点击右上角即可分享
微信分享提示