判断x是否为素数
bool isPrime ( int n)
{
if(n<2) return 0; //0和1不是质数
int tmp =n/2; //判断到n/2
for(int i= 2;i <=tmp; i++)
if(n %i== 0) //如果n与某数相除为0,则不是质数
return 0 ;
return 1 ; //都除不尽,是质数
}
现在复杂度为O(n),注意上面的tmp其实可以直接优化到sqrt(n),原因:
1.如果是质数,则暴力枚举范围没有影响
2.如果是合数,则必有一个质因数<=sqrt(n),反证法:如果所有质因数都>sqrt(n),则相乘必>n,矛盾
下面只需要修改tmp的范围
bool isPrime ( int n)
{
if(n<2) return 0; //0和1不是质数
int tmp =sqrt(n); //判断到n/2
for(int i= 2;i <=tmp; i++)
if(n %i== 0) //如果n与某数相除为0,则不是质数
return 0 ;
return 1 ; //都除不尽,是质数
}
复杂度O(sqrt(n))
上面的只是判断一个数是不是质数,如果要求出素数表,则需要更快的方法。
埃式筛法:
相当于先去掉2的倍数,再去掉3的倍数,再去掉5的,7的,11的……以此类推。
bool IsPrime[Maxn]; //标记i是否为质数
int Prime[Maxn]; //保存求得的质数
int Get_Prime(int n){
int cnt = 0; //统计n以内的质数的个数
memset(IsPrime,true,sizeof(IsPrime)); //所有数一开始都为质数
for(int i=2; i<=n; i++){ //外层循环从2到n
if(IsPrime[i]){ //状态为质数的数必定是新的质数
Prime[cnt++] = i; //将其保存下来,且质数个数加一
for(int j=i+i; j<=n; j+=i) //内层循环将质数i的倍数都置为合数
IsPrime[j] = false;
}
}
return cnt; //返回n以内的质数的个数
}
最后是更快一点的筛法,线性筛,也叫欧拉筛法。
本质上相当于任何一个合数都会被它的最小质因数作为基准删掉一次,
每个合数必定只存在一次最小质数数删除操作,故线性筛时间复杂度为O(n)
int Get_prime(int n){
int cnt = 0;
memset(IsPrime,true,sizeof(IsPrime));
for (int i = 2; i <= n; i++){
if (IsPrime[i])
prime[cnt++] = i;
for (int j = 0; j < cnt; j++){ //遍历质数表
if (i*prime[j] > n) break; //如果超过最大范围,跳出
IsPrime[i*prime[j]] = false; //将以prime[j]]为最小质因数的合数筛掉
if (i%prime[j] == 0) break; //保证只筛到以prime[j]为最小质因数的数
}
}
return cnt;
}