区间找素数的四种方法(埃式筛法、二次筛法、欧拉筛法)、遍历素数筛法
埃式筛法:先假设所有的数都是素数(初始化为true),从第一个素数2开始,把2的倍数都标记为非素数(置为false),一直到大于N;然后进行下一趟,找到2后面的下一个素数3,进行同样的处理,直到最后,数组中依然为true的数即为素数。这种筛法必然会导致一些合数反复被筛,按素数分解,多少种素数就会被筛多少次。
include <stdio.h>
include <string.h>
include <stdbool.h>
include <math.h>
define N 100
int main()
{
int n;
int count=0;
bool vis_array[N+1];
memset(vis_array,true,sizeof(vis_array));
for(int i=2;i<=sqrt(N);i++)
{
if(vis_array[i])
{
for(int j=2;j*i<=N;j++)
{
vis_array[j*i]=false;
}
}
}
for(int i=2;i<=N;i++)
{
if(vis_array[i]) count++;
}
printf("%d",count);
}
二次筛法:从一个素数的平方开始筛,这样能避免在这个平方前的数被这个素数筛。但在平方之后的数仍会被这个素数反复筛。
include <stdio.h>
include <string.h>
include <stdbool.h>
include <math.h>
define N 100
int main()
{
int n;
int count=0;
//scanf("%d",&n);
bool vis_array[N+1];
memset(vis_array,true,sizeof(vis_array));
//int prime_array[N+1];
for(int i=2;i<=sqrt(N);i++)
{
if(vis_array[i])
{
for(int j=i*i;j<=N;j+=i)
{
vis_array[j]=false;
}
}
}
for(int i=2;i<=N;i++)
{
if(vis_array[i]) count++;
}
printf("%d",count);
}
欧式筛法:用合数与素数乘法,素数与素数的乘法去筛将来的数,同时当这个数被更小的素数整除,就不必再用这个数去运算,保证每个合数只会被它的最小质因数筛去,因此每个数只会被筛一次。
include <stdio.h>
include <string.h>
include <stdbool.h>
include <math.h>
define N 100
int main()
{
int n;
int count=0;
bool vis_array[N+1];
memset(vis_array,true,sizeof(vis_array));
int prime_array[N+1];
for(int i=2;i<=N;i++)
{
if(vis_array[i]) prime_array[count++]=i;
for(int j=0;j<count&&prime_array[j]*i<=N;j++)
{
vis_array[prime_array[j]*i]=false;
if(i%prime_array[j]==0) break;
}
}
printf("%d",count);
}
我自己写的一个算法与欧拉可能差不多,每找到一个素数就用一个数组存起来,遍历的时候数,从素数数组最小的数开始除,能整除就不是合数,这样也能保证一个数被最小的素数筛去。
include <stdio.h>
int judge(int n,int a[],int len)
{
for(int j=0;j<len;j++)
{
if(n%a[j]==0) return 0;
}
return 1;
}
int main()
{
int n;
int prime_array[100000]={2};
int len=1;
scanf("%d",&n);
for(int i=3;i<=n;i++)
{
if(judge(i,prime_array,len))
{
prime_array[len++]=i;
}
}
printf("%d",len);
}
综合比较来看,前面三种不适合处理较大区间的素数,因为要开一个与最大数等大的数组去标记,第四种只要开一个大致与区间素数相等的素数数组,但时间复杂度不知道如何。
一个简单估算区间素数的方法是x/lnx。

浙公网安备 33010602011771号