欧拉线性筛素数

欧拉线性筛素数

原理:

简单说明一下,其筛选的原理就是,当一个数是素数时,这个数的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的地方。

猜你喜欢

转载自blog.csdn.net/kente_k/article/details/80464279