3 筛选法求素数

描述
请使用筛选法输出 [a, b] 之间的所有素数。
输入
输入数据有多组,每组数据占一行,每行 2 个正整数 a 和 b,其中 2<=a<=b<=1000000。
输出
每组数据按从小到大的顺序输出 [a, b] 中所有的素数,每行最多输出 10 个素数。每组数据之后空一行。
样例输入
2 3
2 50
样例输出
2 3
2 3 5 7 11 13 17 19 23 29
31 37 41 43 47

筛法的思想特别简单:对于不超过n的每个非负整数p,删除2p,3p,4p,...,当处理完所有数之后,还没有被删除的就是素数。如果用vis[i]表示i已经被删除,筛法的代码可以写成:

memset(vis,0,sizeof(vis));

for(int i = 2; i<=n;i++){
    for(int j = i*2; j<=n; j+=i){
        vis[j] = 1;//删除
    }
}

尽管这份代码已经很高效了,时间复杂度为O(nlogn),但是仍然可以继续改进。即内层循环不必从i*2开始----它已经在i=2时被筛掉了,同理,内层循环也不必从i*3开始,也不必从i*4开始,......,以此类推,而应当从i*i开始,思考一下为什么?(因为 外层循环中,i依次从2,3,...一直变到i-1,而对于每个i,内层循环中的j都会依次累加i)

因此筛法可以做以下改进:

	int m = sqrt(n + 0.5);
	memset(vis,0,sizeof(vis));
	for(int i=2;i<=m;i++){
		for(int j=i*i;j<=n;j+=i){
			vis[j]=1;//删除 
		}
	}
#include<stdio.h>
#include<cstring>
#include<cmath>
#define N 10000000
char vis[N];//memset函数处理的是字符数组 
int main(){
	memset(vis,0,sizeof(vis)); 
	
	int m = sqrt(N + 0.5);
	memset(vis,0,sizeof(vis));
	for(int i=2;i<=m;i++){//初始化vis数组,相当于建表 
		for(int j=i*i;j<=N;j+=i){
			vis[j]=1;//删除(意味着把j从素数列表中排除) 
		}
	}
	//后续直接查表 
	int a,b;
	while(scanf("%d %d",&a,&b)!=EOF){
		int count=0;
		for(int i=a;i<=b;i++){
			if(vis[i] == 0){
				printf("%d ",i);
				
				count++;
				if(count%10==0){//一行最多打印10个数据 
					printf("\n");
				}
			}
		}
		if(count%10!=0){//为下一组数据的输出预留空间,且要防止在上一行中已经进行了换行。 
			printf("\n");
		}
	} 
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jiuweideqixu/article/details/87855984