关于埃式筛的学习进程C语言

问题:求1-e6之间的素数个数;

首先看到这里我一开始就用了这个代码:出现了这样的结果

 我百思不得其解,明明和学的一样呀,怎么会一直黑的,后来才知道原来是求得太慢了,还没出结果

 修改一下就快多了

当然要在头文件加一个<math.h>来支持开根号函数sqrt函数的使用,而i<=的等于是为了防止特殊情况的使用如25开根号后为5而它是素数,如果没有等号的话就会使程序错误判断为25为素数,这里可以自己理解一下,而为什么是开根号呢?那是因为一个数它的因子一定有一个比其本身开根号更小,还有一个就是更大,可以自己试试,而我们求素数只要有一个不是1和本身的因子就不是素数,而这里还有一个我之前一直不明白的东西,我们要求的是素数,为什么在循环里的条件不可以是if(n%i!=0)呢?不是更简单吗?其实自己模拟之后才知道一个数n要除以很多个i直到都不可以整除才是素数,而这里刚刚那个条件表达式的意思是只要有一个不可以被整除就行了,明显不满足。还有一个问题就是:一定要记清1不是素数!!!!

我就已经觉得很快了,但要写蓝桥杯的题还是有时间的限制,所以我们还可以精进如这里因为开根号sqrt速度比较慢,我们可以把它进行平方,有i*i<=n;注意这里还有一个问题,就是如果数字太大了,比如1e6*1e6的范围已经超过了int的范围造成溢出,溢出的会变成负数,除非加上unsigned所以我们可以把一个i移过去变成这样看下时间

虽然除法比乘法慢一些,但处理了刚刚的问题,比开根号时间变短了,当然如果数字越大,差距也会越大; 

然后我们来对它进行改进:1.我们对一个程序的简化无非是代码的长度,循环的次数和范围等,而这个我们目前对1-1e6求的素数最简便也只是1-sqrt(n)次循环;这样的话,其实没必要,我们可以想一下,一个非素数一定可以拆成一个素数乘以另一个数,可以自己试一下,如果2是素数,而2*i的话就一定不是素数直接排掉,我们先看代码:

 这里我们可以看到有几个不同于之前的点:1.首先,我们对它进行了标记,用a[]数组进行0和非零标记,我们把零作为素数的标记,非零是合数的标记;

2.其次,我们去掉了那个判断素数的函数,(这个我也是想了好久的);

3.还有就是它多了一个循环而且循环有点奇葩(我刚开始一直不能理解);

这三点不同都极大地简化了程序,我们来对它进行分析,1情况可以理解为让我们便于用一次大循环筛去更多的合数,在原来的代码中,我们要筛去一个数要先在大循环里一次小循环里循环n开根号次如我要判断17是不是素数,我先得过去第十七次大循环,在这个大循环里面分别除以2-sqrt(n),每个数循环一次才可判断17是否是素数;而在修改了之后的埃式筛法我们要判断17是不是素数的话就很简单了:首先要进行一次循环判断它a[17]是否是被求前面的时候赋值了一,如果被赋值了,就说明17是前面的某一素数和另外一个除1和它本身数的的积,那么它就不是素数,!a[17]就是零,就不进入循环,(要弄明白在条件表达式或是循环里面的括号里0表示假就不执行,非零则是真(这里注意下:我的数组定义在了函数外面,是会主动给元素赋值为零的)这里解释一下为什么​​​​​if(​!a[i])就表示素数了,其实单看这一个还真看不出来,可以把思维放宽一下,首先抓住我们的主思想就是一个非素数一定可以拆成一个素数乘以另一个数,而要想开始筛的话就先让第一个进来的数为素数,所以我们从二开始,可以进来这里有一点要注意的:就是我们刚开始把a[i]=0当做素数,而进入循环的if条件却又是!a【i】刚开始来说都是1;这不是弄混了,而是由于是一个桥妙的设计因为对电脑来说值为非零就是真,我们要先让2进去,等下其他的本就是非素数的a【i】就会被赋值成1就进不来了,而这里的if条件内的东西在前面数字的循环后都不是那些数的积,也就是都没被赋值及标记为1就代表它是素数了反之就进入循环,这里的j=i*i认为是两个素数(不是素数的i进不了这个循环,原因看粉红粗体字)相乘,而当j<=n时就截止了其实在这里面的循环里只是为了以后的数做判断,把十七作为因子的数标记为1;解释一下那个末尾的里面for循环的表达式三,这里的意思是就是说,如果i=3的话,程序不仅要把3的平方9标记,还要标记三的倍数;

最后来总结一下关于埃式筛法和前面的不同:改进之前,程序都在主动的替数找是否有因子,而埃式筛法则是在巧妙的利用循环让小素数的因子进来的同时为其他的数找因子;

最后用晓风的话来勉励自己:世事皆可视作如是观,有浪但船没沉,何妨视作无浪,有陷阱,但人未失足,何妨视作坦途!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值