筛选法求素数
一、一般求素数的方法:一个数n的因子不会超过sqrt(n)。
代码如下:C/C++代码
#include<stdio.h> #include<math.h> voidprime(int n) { int i=2; while(i<=sqrt(n)) if(n%i++==0) return; printf("%d ",n); } intmain() { int i,m,n; scanf("%d%d",&m,&n); for(i=m;i<=n;i++) prime(i); return 0; }
二、筛选素数的方法不是直接判断一个数是不是素数,而是将不是素数的数全部去除,剩余的就是素数了。
1.如果区间包含1,首先将1标记为非素数。
2.从下一个最小的素数a开始,将该素数的倍数(2a,3a,……,ka)全部标记为非素数。
3.从a的后面找下一个最小的素数,重复2操作。
4.重复2,3操作,直到所有元素都筛选完为止。
例如:筛选1到25之间的素数
①按部就班地按上面的4步做,第一步,将1标记为非素数;第二步,找下一个素数a=2,标记2的倍数4,6,8,……,22,24;第三步,重复第二步,这时a=3,标记6,9,……,21,24;第四步,重复第二步第三步,a=5,a=7,a=11,a=13,a=17,a=19,a=23
步骤如下图所示:
相应的代码如下:C/C++代码
#include<stdio.h> #include<iostream> #include<string.h> using namespace std; #define N 8099999 bool prime[N]; __int64 num[N],count; void getprime() { __int64 i,j; memset(prime,0,sizeof(prime)); count=0; for(i=2;i<=N;i++) { if(prime[i]==0) { num[count++]=i; } for(j=2*i;j<=N;j+=i) if(prime[j]!=1) prime[j]=1; } } int main() { __int64 i; getprime(); for(i=0;i<count;i++) printf("%I64d ",num[i]); return 0; }
②当我们再看看上面的步骤时,我们发现有些非素数不只标记一次,例如6这个数字,当a=2和3时都被标记,那么如果我们只标记一次,就会节约一定的时间,这样我们就可以优化程序。同时我们还可以发现,当a=2时,我们只需从2x2=4开始标记2的倍数;当a=3时,上面是从6开始标记的,其实我们只需从3x3=9开始标记3的倍数即可(因为6已经在a=2时被标记);当a=5时,上面是从10开始标记的,其实我们只需从5x5=25开始标记5的倍数即可(因为10、20已经在a=2时被标记,15已经在a=3时被标记)。
过程如下图所示:
根据刚刚的方法,我们可以有以下代码:
#include<stdio.h> #include<string.h> //N代表要求[0,N]区间的上限 #define N 5000000 //数组prime用来标记非素数 bool prime[N]; //数组p储存素数,count记录素数的个数 __int64 p[N],count=0; //筛选素数的函数 void getprime() { __int64 i,j; memset(prime,0,sizeof(prime)); for(i=2;i<=N;i++) { if(prime[i]==0) { p[count++]=i; for(j=i*i;j<=N;j+=i) prime[j]=1; } } } int main() { getprime(); //输出区间[0,N]之间的所有素数 for(int i=2;i<count;i++) printf("%I64d ",p[i]); return 0; }
//N代表要求[0,N]区间的上限 #define N 5000000 //数组prime用来标记非素数 bool prime[N]; //数组p储存素数,count记录素数的个数 __int64 p[N],count=0; //筛选素数的函数 void getprime() { __int64 i,j; memset(prime,0,sizeof(prime)); for(i=2;i<=N;i++) { if(prime[i]==0) { p[count++]=i; for(j=i*i;j<=N;j+=i) prime[j]=1; } } }
原文地址:http://blog.csdn.net/yanghuaqings/article/details/38437133