线性筛选素数。。。。线性哦

来源:互联网 发布:php正则去掉html标签 编辑:程序博客网 时间:2024/06/08 06:10

上一篇一道题目用到了筛选素数,不过是那个只需要求3400以内的,比较少,无所谓,关键是如果要求1000000以内的,再直接求就不行了,太慢了。

下面给出两个自己用的模版,并解释解释,为何这样能够很快计算出素数。

代码1,这个有点长,但是很好理解

#include <stdlib.h>#include <stdio.h>#include <string.h>int prime[100000];bool s[1000010];void Prime()//求素数{    int i,j,k,t;        for (i=2;i<=1000000;i+=2) s[i]=0;    for (i=1;i<=1000000;i+=2) s[i]=1;    s[1]=0; s[2]=1;    for (i=3;i<=1010;i+=2)//如果要求10000以内的素数,你至少要看i%sqrt(10000)都不可约才行,这也是为什么1000000以内只要i<=1000就行了的道理    {        if (s[i])        {            k=2*i;//应为所有偶数已经剔除,所以此处t=3*i(相当于)也就是此次剔除的仍是奇数,所以避免了重复剔除偶数,速度快。            t=i+k;            while (t<=1000000)            {                s[t]=0;                t=t+k;            }        }    }    k=1; prime[1]=2;    for (i=3;i<=1000000;i+=2)    {        if (s[i]==1) { k++; prime[k]=i; }    }    prime[0]=k; }


上面这个实际上就是先踢出了所有偶数,然后呢,以后要踢出的只能是奇数,否则你就重复预算了。k=2*i 是个偶数,i是奇数,3*i也是奇数,那么每次t=i + k都是奇数。所以每次去除的都是奇数倍了。

 

这样处理后基本上每个数只判断一次就知道是不是素数了,所以是线性。。。

 

代码2:难理解一点

const int M = 3000500;int p[400010], pNum;bool f[M];void Prime(){int i, j;for(i = 2; i < M; i++) {if(!f[i]) { p[pNum++] = i; }for(j = 0; j < pNum && p[j] * i < M; j++ ) {f[p[j]*i] = 1;if(!(i%p[j]))break;}}}


这个其实和上面那个是同一个道理。首先f[i]==0就是素数,从2开始。然后我们要去除已经取得素数的i倍的数,f[p[j]*i] = 1;

关键就是下面那句话不好理解,因为正是那句跳出循环才能保证筛选素数是线性的。

为什么i能除尽p[j]这个素数就跳出呢?

其实可以简单证明一下:

合数可以由一个质数数与另一个数相乘得到
而同时假设合数a=质数b×质数c×一个数d
令e=c × d,假设b ≥ c,e为合数,令f=d × b
a=f × c ,其中c
即大的质数和该合数的乘积可用一个更大的合数和比其小的质数相乘得到
这也是if(!( i % prime[j]))break;的含义,这也是线性筛法算质数表的关键所在

 

举个例子:

比如i = 9,现在素数是2 3 5 7

进入第二重循环了,f[2 * 9] = 1;f[3 * 9] = 1;

这个时候9%3==0,要跳出了,为什么不做f[5* 9] =1;呢?

因为5 * 9 可以用3 * 15来代替,如果这个时候你计算了,那么到i=15的时候这个数还会被重复计算一次,所以这里大量避免了重复运算,所以也就节省了时间。

 

这里总结一句话就是,一个大的合数和这个能除尽的质数的乘积,一定能被一个比起小的质数和合数更大的合数乘积来代替。

不懂的时候想想 5*9 = 5*3*3 = 3*15就是这个道理。

 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小孩子不爱写作业怎么办 小孩不交作业怎么办 小孩子不喜欢写作业怎么办 实行两票制 一品红会怎么办 跳舞之后浑身疼怎么办 事业编体检怀孕怎么办 辞职后报到证怎么办 学生早上起床困怎么办 延期毕业报到证怎么办 学校报到证丢失怎么办 生育险不满一年怎么办 产假结束上班宝宝怎么办 辞职后生育津贴怎么办 员工要不到工资怎么办 试用期不发工资怎么办 单位不给探亲假怎么办 工作5.5天周六怎么办 不爱运动的幼儿怎么办 总跟孩子生气怎么办 小孩经常感冒发烧怎么办 家里出现皮球虫怎么办 第一天教幼儿园怎么办 幼师遇到家长投诉怎么办 小孩喜欢玩手机怎么办 幼师掐孩子胳膊怎么办 孩子喜欢抓人怎么办 小孩顽皮不听教怎么办 出现了心理异常怎么办 想问下心理出问题该怎么办 大班幼儿爱说话怎么办 孩子不喜欢去幼儿园怎么办 别人抢宝宝玩具怎么办 新生儿抱淘气了怎么办 野兔子吃葵花怎么办 烫伤了怎么办安全反思 安全教案触电了怎么办 烫伤了怎么办儿歌导入 生病了怎么办教学反思 大班安全《烫伤了怎么办》 安全教案热了怎么办 身上有色素斑怎么办