天天看點

篩質數的三種方法時間複雜度及其實作:普通篩法,埃氏篩法,線性篩法

篩質數的三種方法時間複雜度及其實作:普通篩法,埃氏篩法,線性篩法

普通篩法 O(nlogn)

普通篩法做法是用每一個合數的所有因子篩去目前合數,比如24被2,3,4,6,8,12篩去6次

int get_primes(int n )
{
    for(int i = 2; i <= n ; i ++ )
    {
        if(!st[i])  //如果是質數
        {   primes[cnt ++] = i;
        }
        for(int j = i * 2 ; j <= n ; j += i)  st[j] = true;
        //不管目前i是合數還是質數,都用來篩掉後面它的倍數
    }
}
           

埃氏篩法 O(nloglogn)

埃氏篩法做法是隻用每一個合數的質因子篩去目前合數,比如24會被2,3篩去兩次

int get_primes(int n )
{
    for(int i = 2; i <= n ; i ++ )
    {
        if(!st[i])  //如果是質數
        {   primes[cnt ++] = i;
            for(int j = i * 2 ; j <= n ; j += i)  st[j] = true;  
            //隻用質數i篩掉它的倍數(合數),也可以篩掉所有合數
        }
    }
}
           

線性篩法 O(n)

線性篩法做法是隻用每一個合數的最小質因子篩去目前合數,比如24隻會被2篩去一次

int get_primes(int n )
{
    for(int i = 2 ; i <= n ; i ++ )
    {
        if(!st[i]) primes[cnt ++] = i;
        for(int j = 0 ; primes[j] <= n / i ; j ++ ) 
//判斷條件解釋:我們用primes[j]篩掉合數primes[j] * i,隻用篩掉小于n的合數就可以了
        {
            st[primes[j] * i] = true;   
/*
每個合數隻會被自己的最小質因子篩,隻會被篩一次,是以O(n)
##如何證明目前primes[j]一定是primes[j] * i 的最小質因子?
因為當i % primes[j] != 0時,說明此時周遊到的primes[j]不是i的質因子
那麼隻可能是此時的primes[j] * i的最小質因子,
是以primes[j] * i的最小質因子就是primes[j];
就保證了用primes[j] * i的最小質因子篩去primes[j] * i
當 i % primes[j] == 0時,說明i的最小質因子是primes[j],是以primes[j] * i的最小質
因子也就應該是prime[j],下一輪循環接着用st[primes[j+1] * i] = true去篩合數時,
就不是用最小質因子去更新了,因為i有最小質因子primes[j],primes[j] < primes[j + 1]
此時的primes[j + 1]不是primes[j + 1] * i的最小質因子,
此時就應該退出循環,避免之後重複進行篩選。
*/
            if(i % primes[j] == 0) break;   
        }
    }
}
           

繼續閱讀