筛选法求素数

先证明一个结论:只要一个数n不能所有的从2到(n的开方)之间的素数整除,那它就一定是质数。

假如n是合数,那么n肯定能表示成x*y,1<x,y<n

不失一般性,如果x>=(n的开方),则有y<=(n的开方)

因此如果n是合数,就能在2~(n的开方)范围内找到它的一个因子

即一个数是否是素数是查找范围不大于这个数的开方

因此,如果n不能所有的从2到(n的开方)之间的素数整除,(因为n的因子或者为素数,或者为合数,是合数的话肯定能表示成素数的乘积)那么它一定是素数,换句话说合数肯定有素数因子

基于这个思想,最简单的素数筛选算法如下,时间复杂度O(n*sqrt(n)):

int num = 0;
int prime[N];
for(i = 4; i <= N; i++)
{ 
    for(j = 2; j <= sqrt(i); j++) 
    { 
        if(i%j == 0) break;
             prime[num++] = i;
     }
}
 
 

 上面的算法没有一点的复杂度,估计连算法都称不上吧。 

我们可以利用素数筛法的思想:当一个数是素数时,它的倍数肯定是合数。基于前面的推论有了以下的筛选算法:

bool prime[N+1];
for(i = 0; i < N+1; i++)
下标为奇数的标为true,下标为偶数的标为false
for(i = 3; i <= sqrt(N); i++)
{
     if(prime[i])
     {
          for(j = i+i; j < N+1; j+=i)
              prime[j] = false;
     }
}
最后输出下标为true的元素即可

 

 可以考虑进一步优化算法。 

首先能想到的是偶数肯定不是素数,因此prime只表示奇数,不表示偶数,即0表示3,1表示5,2表示7,3表示9....下标i表示的整数为(2i+3),算法的复杂度减少了不只一半的循环时间。

bool prime[N+1];
for(i = 0; i < N+1; i++)
下标为奇数的标为true,下标为偶数的标为false
for(i = 3; i <= sqrt(N); i=i+2)
{
     if(prime[i/2-1])
     {
          for(j = 2*i+i; j < N+1; j+=2*i)
              prime[j/2-1] = false;
     }
}
最后输出下标为true的元素即可
进一步分析,可以发现,有些元素重复筛过的,例如合数15在素数3和素数5时都遍历了

由前面的推论的可以知道:n如果是素数的话,那么就肯定能在n开方的范围内找出它的因子,从而判断它是否为素数。逆向思考,为了判断n是否为素数,由于我们已经遍历了n开方内的所有素数i(的所有合数),小于i平方的数要么是素数,要么是合数是已经确定的。因此,当遍历i的合数是时,我们只需从i平方开始,小于i平方的数无需重复遍历。好像有点绕,说白了还是推论的思想。

举个例子,3(i=0)直接从下标[3](对应值为9)开始筛,5(i=1)从下标为[11](对应值25)开始筛。7(i=2)本来应该从下标为[9](对应值21)开始筛,但是由于[9]被筛过了(被i=0筛过),而[16]也已经被5(i=1)筛过。于是7(i=2)从[23](就是2*23+3=49)开始筛。于是当外围循环为下标为i时,内循环的下标是从i+[(2*i+3)2-(2i+3)]/2即i*(2*i+6)+3开始筛的。

bool prime[N+1];
for(i = 0; i < N+1; i++)
下标为奇数的标为true,下标为偶数的标为false
for(i = 3; i <= sqrt(N); i=i+2)
{
     if(prime[i/2-1])
     {
          for(j = i*i; j < N+1; j+=2*i)
              prime[j/2-1] = false;
     }
}
最后输出下标为true的元素即可
代码还没验证过,尚需完善...



 
 
 
 
 
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值