欧拉线性筛素数
原理:
简单说明一下,其筛选的原理就是,当一个数是素数时,这个数的2,3,4,,,,n倍肯定都不是素数。
代码:
bool isnotprime[INF]={1,1}; //isnotprime[i] 判断i是否为素数 0代表是素数 1代表不是素数
int prime[INF]={0}; //prime[i]为第i个素数,从0开始
int num=0; //num为素数个数;
void setprime(int n) //求小于n的素数;
{
num=0;
for(int i=2;i<n;i++)
{
if(!isnotprime[i])
{
prime[num++]=i;
}
for(int j=0;j<=num&&i*prime[j]<n;j++)
{
isnotprime[i*prime[j]]=1;
if(!(i%prime[j]))
break;
}
}
}
详解:
bool isnotprime[INF]={1,1}; ///即isnotprime[0]=1;isnotprime[1]=1;
因为0和1都不是素数,所以置为1。
for(int i=2;i<n;i++)
{
if(!isnotprime[i])
{
prime[num++]=i;
}
第一层for循环,判断 i 是否是素数。i=2时,isnotprime[ 2 ]=0,即是素数。将其放入素数数组prime里面。素数个数加1。
for(int j=0;j<=num&&i*prime[j]<n;j++) {
isnotprime[i*prime[j]]=1;
if(!(i%prime[j]))
break;
}
}
第二层for循环,将现有的所有素数的第 i 倍筛选掉。即 isnotprime[ i * prime [ j ] ]置为1。
i=2时,仅能将4筛掉,即isnotprime[ 2 * 2 ]=1;
if(!(i%prime[j]))
break;
原理是利用了每个合数必有一个最小素因子,每个合数仅被它的最小素因子筛去正好一次,当 i 能整除 prime[ j ],那么i * prime[ j+1 ] 这个合数肯定被 prime[j] 乘以某个数筛掉,因为 i 中有prime[j]且 i * prime[ j+1 ]中也有prime[ j ]。
举个例子:
当 i = 8,prime[ ] = 2,3,5,7;
i * prime[ ] = 16,24,40,56;
因为8 % 2 = 0,所以24,40,56,可以不筛,直接break;
就如上面那句话所说的,当8能整除2时,8乘以 下一个素数3 的值24,将会被12乘以2筛掉。
即24 = 8 * 3=(2 * 4) * 3 = 2 * (4 * 3) = 2 * 12; 被12筛掉
40 = 8 * 5=(2 * 4) * 5 = 2 * (4 * 5) = 2 * 20; 被20筛掉
56 = 8 * 7=(2 * 4) * 7 = 2 * (4 * 7) = 2 * 28; 被28筛掉
这些数后面会被筛掉,即 i = 12,20,28时。所以现在就不用筛选,降低时间复杂度。
代码执行过程:
i | 最新确定的素数( prime[] ) | 最新确定的非素数( isnotprime[] ) |
---|---|---|
2 | 2 | 4 (2 * 2) |
3 | 3 | 6 (3 * 2)、9 (3 * 3) |
4 | 8 (4 * 2) | |
5 | 5 | 10 (5 * 2)、15 (5 * 3)、25 (5 * 5) |
6 | 12 (6 * 2) | |
7 | 7 | 14 (7 * 2)、”21”(7 * 3)、”35”(7 * 5)、”49”(7 * 7) |
8 | “16”(8 * 2) | |
9 | “18”(9 * 2)、“27”(9 * 3) | |
10 | “20”(10 * 2) | |
11 | 11 | “22”(11 * 2)、”33”(11 * 3)、”55”(11 * 5)、”77”(11 * 7)、”121”(11 * 11) |
12 | “24”(12 * 2) | |
13 | 13 | “26”(13 * 2)、”39”(13 * 3)、”65”(13 * 5)、”91”(13 * 7)、”143”(13 * 11)、“169”(13 * 13) |
14 | “28”(14 * 2) | |
15 | “30”(15 * 2)、“45”(15 * 3) |
此表为求15以内的素数代码执行过程。
打引号的为大于15的非素数,可以不筛。
加粗的为break的地方。