C++区间质数筛选(2种方法)

引子:Question:

给定两个数min,max,求出[min,max]区间的所有素数


C++的区间质数筛选,有两种方法。

Eratosthenes Algorithm

第一种就是Eratosthenes算法,该算法基于一个思想:对于任意的整数x,2x,3x,4x....一定不是质数。那好以二为起始点,很容易写出一下代码:

Code(Eratosthenes-1)

#include<cstdio>
#include<cstring>
bool vis[32768];
int main(){
	int min,max;
	scanf("%d %d",&min,&max);
	memset(vis,1,sizeof(vis));
	vis[1]=0,vis[0]=0;
	for(int i=2;i<=max;i++){
		if(vis[i]){
			if(i>=min){
				printf("%d ",i);
			}
		}
		for(int j=i;j<=max;j+=i){
			vis[j]=0;
		}
	}
	return 0;
}

我再给一张图,来解释它的运算过程:

 我们会发现j可以从i*i开始也不会影响结果。观察发现比i*i小的数在之前能够保证已经筛去了。这样可以减少不必要的冗余计算(重复标记)

Code(Eratosthenes-2)

#include<cstdio>
#include<cstring>
bool vis[32768];
int main(){
	int min,max;
	scanf("%d %d",&min,&max);
	memset(vis,1,sizeof(vis));
	vis[1]=0,vis[0]=0;
	for(int i=2;i<=max;i++){
		if(vis[i]){
			if(i>=min){
				printf("%d ",i);
			}
		}
		for(int j=i*i;j<=max;j+=i){
			vis[j]=0;
		}
	}
	return 0;
}

时间复杂度:O(N log log N)

但即使这样,也无法避免重复计算!

如12被标记了两次,3*4与2*6。所以说,避免冗余运算是提高算法运算效率的关键,那么有没有这样一种完美的算法呢?有,那就是线性筛法!


线性筛法 Algorithm

先上代码:

Code(线性筛法)

#include<cstdio> 
#include<cstring>
int vis[32768];
int prime[32768];
int main(){
	int min,max;
	scanf("%d %d",&min,&max);
	memset(vis,0,sizeof(vis));
	int tot=0;
    for(int i=2;i<=max;i++){
    	if(vis[i]==0){
    		prime[++tot]=i;
    		vis[i]=i;
		}
		for(int x=1;x<=tot;x++){
			if(prime[x]*i>max || prime[x]>vis[i])break;
			vis[prime[x]*i]=prime[x];
		}
	}
	for(int i=1;i<=tot;i++){
		if(prime[i]>=min){
			printf("%d ",prime[i]);
		}
	}
	return 0;
}

 我们从本质上思考重复计算的原因,发现我们对于同一个数的计算方式不同。那么怎样才能确定一个唯一的计算方式呢?关键是找质因子,因为每一个大于1的正整数都能分解为若干个质数的乘积。给一张图启迪你一下:

这样时间复杂度降到了O(N)

 撒花,完结。。。

 End~~~

谢谢支持,欢迎评论留言。

 


版权声明:本文为way_back原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。