浅谈(C语言)Eratoshenes筛法寻找素数与一般算法
爱拉托塞斯筛法(Eratoshenes筛法)是一种寻找素数的方法,又称平凡除法或厄拉托塞斯(Eratoshenes)筛法。
其是应用定理“设n是正整数,如果对虽有的素数p≤√n,都有p不能整除n,则n一定是素数.”得到的一个寻找素数的确定性方法。下面给出具体描述:
对任意给定的正整数N,要求出所有不超过N的素数。列出N个整数,从中删除不大于√N的所有素数P1,P2,P3,……,Pk的倍数(除素数P1,P2,P3,……,Pk外)。具体的是依次删除,
P1的倍数:2·P1,3·P1,4·P1,……,[N/P1]·P1;
P2的倍数:2·P2,3·P2,4·P2,……,[N/P2]·P1;
P3的倍数:2·P3,3·P3,4·P3,……,[N/P3]·P1;
…………
Pk的倍数:2·Pk,3·Pk,4·Pk,……,[N/Pk]·P1.
余下的整数(不包括1)就是所有求的不超过N的素数([x]表示小于或等于x的最大整数)。
#C/C++##笔经#
其是应用定理“设n是正整数,如果对虽有的素数p≤√n,都有p不能整除n,则n一定是素数.”得到的一个寻找素数的确定性方法。下面给出具体描述:
对任意给定的正整数N,要求出所有不超过N的素数。列出N个整数,从中删除不大于√N的所有素数P1,P2,P3,……,Pk的倍数(除素数P1,P2,P3,……,Pk外)。具体的是依次删除,
P1的倍数:2·P1,3·P1,4·P1,……,[N/P1]·P1;
P2的倍数:2·P2,3·P2,4·P2,……,[N/P2]·P1;
P3的倍数:2·P3,3·P3,4·P3,……,[N/P3]·P1;
…………
Pk的倍数:2·Pk,3·Pk,4·Pk,……,[N/Pk]·P1.
余下的整数(不包括1)就是所有求的不超过N的素数([x]表示小于或等于x的最大整数)。
通过上面的的解释,我们知道爱拉托塞斯筛法是指从2到N删去√N内所有素数的2倍、3呗、4呗、……、[N/P1]倍,剩下的就是N内的素数。而通常情况下我们求解N内的素数的一般方法为,i从2到N循环,依次判断i能否被2到√i间的所有数整除,由此来找出N内的素数。看似爱拉托塞斯筛法简单,其实分析得其算法复杂度与循环次数比基本算法要复杂许多,下面分享本人写的2种算法代码及其速度比较:
1.下面是本人写的爱拉托塞斯筛法寻找素数的算法代码:
#include <stdio.h> #include <stdlib.h>
#include <math.h>
#include <conio.h>
#include <time.h>
void main( )
{
long max,k ,k1,i,j,m,ad,sd;
sd=0;
ad=0;
long *a;
long start,end;
printf("请输入一个数:");
scanf("%ld",&max); //输入一个数
start = clock();
k=(long)sqrt((float)max);
printf("开平方后取整k=%ld",k);
if(NULL==(a=(long*)malloc(sizeof(long)*max)))
{
printf("memmery error!\n");
exit(1);
}
for(i=0;i<max;i++){ //初始化数组a,记录1~max
a[i]=i+1;
}
long *s; //s记录K内的素数
if(NULL==(s=(long*)malloc(sizeof(long)*k)))
{
printf("memmery error!\n");
exit(1);
}
for(i=0;i<k;i++){ //初始化数组s
s[i]=0;
}
for(m=2;m<=k;m++){ //求k内的素数
k1=int(sqrt(double(m)));
for(i=2;i<=k1;i++){ //while(m%i && i<=k1)
if(m%i==0) // i++;
break; //
}
if(i>k1){
s[sd]=m;
sd++; //sd即为k内素数的个数
}
}
printf("\n%ld内的素数有:\n",k);
for(i=0;i<sd;i++){
if(s[i]!=0)
printf("%ld\t",s[i]);
}
for(i=2;i<max;i++){ //爱拉托塞斯筛选
for(m=0;m<sd;m++){
for(j=2;j<=(max/s[m]);j++){
if(a[i]==(j*s[m]))
a[i]=0;
}
}
}
end = clock();
printf("\n不超过%ld的素数有:\n",max);
for(i=1;i<max;i++){
if(a[i]!=0)
printf("%ld\t",a[i]);
}
printf("用时%ld毫秒\n",end-start);
getchar();
getchar();
}
编译运行,输入10000,其结果如下,运行时间为863毫秒:
2.下面是本人写的基本一般寻找素数的算法代码:
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <conio.h> #include <time.h> void main() { long max,k,i,m; long start,end; printf("请输入一个数:"); scanf("%ld",&max); //输入一个数 start = clock(); printf("\n%ld内的素数有:\n",max); for(m=2;m<=max;m++){ //求k内的素数 k=int(sqrt(double(m))); for(i=2;i<=k;i++){ //while(m%i && i<=k) if(m%i==0) // i++; break; // } if(i>k){ printf("%ld\t",m); } } end = clock(); printf("用时%ld毫秒\n",end-start); getchar(); getchar(); }
编译运行,输入10000,其结果如下,运行时间为81毫秒:
通过上面的比较,发现爱拉托塞斯筛法寻找素数的速度明显比基本算法慢好几倍。
本人技术有限,代码不保证100%完美,些许部分或有不妥或有改善之处,或是你有更好的算法,欢迎评论交流!