初学:
int prime(int n)
{
for(int i=2;i<n;i++)
{
if(n%i==0)
{
return 0;
}
}
return 1;
}
进化:
int prime(int n)
{
for(int i=2;i<=sqrt(n);i++)
{
if(n%i==0)
{
return 0;
}
}
return 1;
}
虽然第二个方法比第二个方法效率更高,但是当数超过10^12次方,就很难实现,这个时候就要需求别的方法。
下面介绍一个时间复杂度在O(sqrt(n)/3)的方法:
int prime(int x)
{
if(x==1)return 0;
if(x==2||x==3)return 1;
if(x%6!=1&&x%6!=5)return 0;
for(int i=5;i<=sqrt(x);i+=6)
{
if(x%i==0||x%(i+2)==0)
return 0;
}
return 1;
}
下面就介绍怎么求一个范围内的所有素数,这个时候就需要两个著名的筛法:埃式筛法和欧拉筛法(也叫作欧拉线性筛,因为是线性,所以要比埃式筛法更优化)
埃氏筛的基本思想:素数的倍数一定不是素数
我们先假设[1,n]上的数全部都是素数,然后从2开始往后遍历,如果当前的i是一个素数,那么进入循环,找到i的倍数,并标记为合数。
bool vis[Max];//true表示不是素数,false表示是素数
int prime[Max],ret;
void Prime()
{
long long i,j;
ret=0;
memset(vis,false,sizeof(vis));
vis[1]=true;
for(i=2;i<Max;i++)
{
if(!vis[i])
{
prime[++ret]=i;
for(j=2*i;j<Max;j+=i)
{
vis[j]=true;
}
}
}
}
下面介绍啥是欧拉筛法
基本原理:由于所有合数都有一个最小质因子,所以在埃氏筛法的基础上,让每个合数只被它的最小质因子筛选一次,以达到不重复的目的。
//欧拉筛法
bool vis[Max];//true代表非素数,false代表素数
int prime[Max];
void Prime()
{
int ret=0;
memset(vis,false,sizeof(vis));//把vis数组全部标记为素数
vis[1]=true;
for(int i=2;i<Max;i++)
{
if(!vis[i])//如果i不是一个素数
prime[ret++]=i;
for(int j=0;j<ret&&i*prime[j]<Max;j++)
{
vis[i*prime[j]]=1;//标记为合数
if(i%prime[j]==0)
break;
}
}
}