素数的线性筛选

来源:互联网 发布:应届生求职软件知乎 编辑:程序博客网 时间:2024/06/08 17:16

出处:http://www.cnblogs.com/Lyush/archive/2012/08/06/2625510.html

线性筛选法之所以称之为线性就是因为其对于每一个合数只用其最小的素因子将其筛选出来。代码如下:

#include <cstdlib>#include <cstdio>#include <algorithm>#define MAXN 1000000using namespace std;int p[1000005], pri[1000005], idx = -1;void GetPrime(){    for (int i = 2; i <= MAXN; ++i) {        if (!p[i]) { // 说明i是一个素数            pri[++idx] = i;        }        for (int j = 0; j <= idx && pri[j]*i <= MAXN; ++j) {// 遍历所有的素因子             p[pri[j]*i] = 1;            if (i % pri[j] == 0) {  // 如果i能够整除pri[j]那么i*pri[j+1]就一定被pri[j]数整除                 break;                }        }    }    printf("idx = %d\n", idx);    for (int i = 0; i <= 100; ++i) {        printf("%d ", pri[i]);    }}int main(){    GetPrime();    system("pause");    return 0;    }


---------------------------------------------------

另一篇文章

出处:http://blog.csdn.net/zhang20072844/article/details/7647763

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

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

#include <stdlib.h>  02.#include <stdio.h>  03.#include <string.h>  04.int prime[100000];  05.bool s[1000010];  06.  07.  08.void Prime()//求素数  09.{  10.    int i,j,k,t;  11.      12.    for (i=2;i<=1000000;i+=2) s[i]=0;  13.    for (i=1;i<=1000000;i+=2) s[i]=1;  14.    s[1]=0; s[2]=1;  15.    for (i=3;i<=1010;i+=2)//如果要求10000以内的素数,你至少要看i%sqrt(10000)都不可约才行,这也是为什么1000000以内只要i<=1000就行了的道理  16.    {  17.        if (s[i])  18.        {  19.            k=2*i;//应为所有偶数已经剔除,所以此处t=3*i(相当于)也就是此次剔除的仍是奇数,所以避免了重复剔除偶数,速度快。  20.            t=i+k;  21.            while (t<=1000000)  22.            {  23.                s[t]=0;  24.                t=t+k;  25.            }  26.        }  27.    }  28.    k=1; prime[1]=2;  29.    for (i=3;i<=1000000;i+=2)  30.    {  31.        if (s[i]==1) { k++; prime[k]=i; }  32.    }  33.    prime[0]=k;   34.}  



下面这个程序:是简化版的:

这个其实和上面那个是同一个道理。首先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就是这个道理。


const int M = 3000500;  02.int p[400010], pNum;  03.bool f[M];  04.void Prime()  05.{  06.    int i, j;  07.    for(i = 2; i < M; i++) {  08.        if(!f[i]) { p[pNum++] = i; }  09.        for(j = 0; j < pNum && p[j] * i < M; j++ ) {  10.            f[p[j]*i] = 1;  11.            if(!(i%p[j]))  12.                break;  13.        }  14.    }  15.}  





2 0
原创粉丝点击