区间找素数的四种方法(埃式筛法、二次筛法、欧拉筛法)、遍历素数筛法

埃式筛法:先假设所有的数都是素数(初始化为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。

posted @ 2020-12-29 23:20  empty_thought  阅读(921)  评论(0)    收藏  举报