素数筛选算法代码与算法分析(普通筛、线性筛)

素数筛选算法

代码传送门1

代码传送门2

理论层面:

怎么筛选出素数?

我们的基本思路是排除掉所有合数,那么留下的就是素数

知道合数可以分解成素数相乘,那么我们只要将不同素数组合相乘后的结果排除掉就可以了

q = p1^a1 * p2^a2 *... pn^an

这里q为合数,pi为质数,ai为幂。

算法框架层面:
首先

构造两个数组,check和prime, check用于标记该数是否是素数,prime是包括所有素数的集合。举例:

check[10] = [0,0,1,1,0,1,0,1,0,0]//初值为0,0表示素数,1表示合数,
                                 //check随着循环而改变

prime[] = [2,3,5,7] //  prime刚开始为空,随着循环迭代而生长
然后

我们可以构造一个循环,从2开始,每次+1,直到要求的范围(比如10000以内)

for(i=2;i<=n;i++)
{}
在循环体内:

我们一定可以保证:

假如循环到了i = a,经过i = 2到i = a-1这么多轮筛选之后,对于第a+1这个数已经可以确定它是不是素数(如果a+1是合数就一定已经被标记过了)

算法思路

素数筛算法,这里有三个层次:

1、判断一个数是否为素数

很简单,不说了,也可以用欧拉定理

2、普通素数筛(埃拉托斯特尼筛法)

主要想法是对于已知的一个素数,那么我们依次排除掉这个素数×2, 这个素数×3, 这个素数×4 … 直到达到要求的范围(比如10000以内)再停止。

3、快速素数筛(欧拉筛法、线性筛)

普通素数筛存在一个问题,就是会进行重复排除, 比如:

2排除122*6会排除一次

当用3排除12时, 3*4又会排除一次

//如果数据规模很大,效率会很低。

快速筛解决了重复的问题,一个合数只会排除一次:

主要想法:假如当前循环到了i=a, 那么依次排除: a * prime[1]、a * prime[2]、a * prime[3]、a * prime[4]…(a乘以所有的已知素数)。 但是如果prime[k] | a, 那么就出现了重复,停止排除(但是a*prime[k]这一项先排除掉),break进入下一个i循环。

停止排除的理由:如果a能被prime[k]整除,那么它在后面的循环中一定会被排除。

证明:

若prime[k] | a,则

a = (a / prime[k]) * prime[k]
//令b = a / prime[k],得到
a = b * prime[k]

设prime[k+]表示表中比prime[k]更大的素数,prime[k-]表示比prime[k]更小的素数,有

a * prime[k+] = b * prime[k] * prime[k+] = (b * prime[k+]) * prime[k]

那么当i = a × prime[k+]时, 知道prime[k-]不整除a和prime[k+], 所以一定可以循环到第(a × prime[k+]) × prime[k],并排除这个数。

证毕!

从数论角度理解:一个数可以分解为多个因数相乘,我们只要排除

最小质因数 × 其它质因数相乘得到的数 = 该数 

这一种情况就可以避免重复,而若prime[k] | a, 说明prime[k] 不是 prime[k] * a 的最小质因数。 更不用说prime[k+]的数,但是从小到大就可以保证prime[k-]和prime[k]是最小的质因数,那么将其排除。
很妙!

理论理解传送门

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值