一:线性素数筛
一般的素数筛思路就是选择出小素数,然后划去小素数得到整数倍,这就是”埃拉托斯特尼筛法”,这种方法会同一个元素进行多次筛选。因此有了另一种优化的线性素数筛法。主要思想是:每一个合数都可以进行质因数分解,所以任何一个合数都可以由最小素因子进行唯一标记。
代码如下:
void quick_prime(int n)
{
memset(prime,0,sizeof(prime));
int cnt = 0;//用于数组下标累计的计数器
prime[0] = 1;// 0 和 1不是素数(当然也不是合数)
prime[1] = 1;
for(int i=2;i<=n;i++)
{
if(!prime[i]) //如果是素数,进行下面的操作
pri[cnt++] = i;
for(int j=0 ; j<cnt && i * pri[j] <= maxn ; j++)//遍历现有的素数
{
prime[i * pri[j]] = 1;
if(i % pri[j] ==0)
break;//防止反复筛选!
}
}
}
- prime数组的值代表下标是否为素数,如果为素数,数组的值为0,非素数为1(包括合数和既不是素数也不是合数的数)
- pri数组存的是素数,从0开始。
- 最主要是break那里,比如12这个数,在普通筛的时候12要被2和3都筛一次,显然这种多余的操作会增加时间复杂度,线性筛中一个数字只被它最小的素因子筛掉,12只被2筛掉,当i等于6的时候2*6==12筛掉12,这时候6%2==0可以break了,如果不break,那么6还会把18筛掉,此时是通过6*3来筛掉18,可是显然18最小的素因子是2,所以当i枚举到9的时候有9*2==18,这样18就又被筛了一次,因此在i等于6的时候不用拿6去筛18,下面用公式来说明:
当p[j]是i的因子时,设i=p[j]* k,因为素因子从小到大枚举,所以p[j]是i的最小素因子,此时i已经无需再去剔除p[j’] * i (j’>j) 形式的合数了,因为p[j’]* i可以写成p[j’]* (p[j]* k)=p[j](p[j’] k),也就是说所有的p[j’]* i将会被将来的某个i’=p[j’]*k剔除掉,当前的i已经不需要了。
也就是说如果这时候的i可以被此素数表示,那么下一个素数与i的乘积所得到的结果存在更小的素数。