一,埃式筛法
埃氏筛法是数学家埃拉托斯特尼所发明的一种比较稳定的求素数方法,他还可以顺带记录下来沿途的素数。
原理:用已经有的素数筛掉未来的非素数。
埃氏筛法的基本思想 :从2开始,将每个质数的倍数都标记成合数,以达到筛选素数的目的。
int slove(int n)
{
int p=0;//用来记录素数的多少
for(int i=0;i<=n;i++)
is_prime[i]=true;//先把它初始化
is_prime[0]=is_prime[1]=false;//人为规定0,1不是素数
for(int i=2;i<=n;i++)//枚举
{
if(is_prime[i])//如果它是素数
{
prime[p++]=i;//计算素数的个数,也记录下了素数
for(int j=2*i;j<=n;j+=i)//用它去筛它的素数
is_prime[j]=false;//它的倍数自然不是质数
}
}
return p;//返回多少个素数
}
其实这段代码还可以优化一下:将j 从 i * i 而不是从 i + i开始,因为 i*(2~ i-1)在 2~i-1时都已经被筛去,所以从i * i开始。
埃氏筛法的缺陷 :对于一个合数,有可能被筛多次。例如 30 = 2 * 15 = 3 * 10 = 5*6……那么如何确保每个合数只被筛选一次呢?我们只要用它的最小质因子来筛选即可,这便是欧拉筛法。
二,欧拉筛法
欧拉函数求法与欧拉筛法求素数也是非常精妙的算法。
欧拉函数是小于n的正整数中与n互质的数的数目,欧式筛法正是围绕着欧拉函数而展开。
原理:以欧拉函数为本体,衍生操作欧式筛法
欧拉筛法的基本思想 :在埃氏筛法的基础上,让每个合数只被它的最小质因子筛选一次,以达到不重复的目的。
先要了解一下特性:
1.若a为质数,phi[a]=a-1;
2.若a为质数,b mod a=0,phi[ab]=phi[b]a
3.若a,b互质,phi[ab]=phi[a]phi[b](当a为质数时,if b mod a!=0 ,phi[ab]=phi[a]phi[b])
代码 :
int n,m[100],phi[100],p[100],nump;
//m[i]标记i是否为素数,0为素数,1不为素数;p是存放素数的数组;nump是当前素数个数;phi[i]为欧拉函数(小于它并与它互质的个数)
int make()
{
phi[1]=1;//人为规定1不是素数
for (int i=2;i<=n;i++)//记录2至n的所有细节
{
if (!m[i])//假如i为素数
{
p[++nump]=i;//将i加入素数数组p中
phi[i]=i-1;//因为i是素数,由特性1得知
}
for (int j=1;j<=nump&&p[j]*i<n;j++) //用当前已得到的素数数组p筛,筛去p[j]*i
{
m[p[j]*i]=1;//可以确定i*p[j]不是素数
if (i%p[j]==0) //看p[j]是否是i的约数,因为素数p[j],等于判断i和p[j]是否互质
{
phi[p[j]*i]=phi[i]*p[j]; //特性2
break;
}
else phi[p[j]*i]=phi[i]*(p[j]-1); //互质,特性3其,p[j]-1就是phi[p[j]]
}
}
}
对于m[p[j]*i]=1 的解释: 这里不是用i的倍数来消去合数,而是把 p里面纪录的素数,升序来当做要消去合数的最小素因子。
参考:https://blog.youkuaiyun.com/qq_39763472/article/details/82428602
https://blog.youkuaiyun.com/qq_41754350/article/details/81609688?tdsourcetag=s_pcqq_aiomsg