1. 程式人生 > 其它 >三種素數篩法(普通篩法、埃氏篩法、尤拉篩法)

三種素數篩法(普通篩法、埃氏篩法、尤拉篩法)

技術標籤:ACM演算法

素數篩法

一般篩法:

一般篩法適用於單個元素的檢驗,就是簡單地對於一個元素 n 從2至 sqrt(n)進行檢驗能否整除,有一個就不是素數。

程式碼如下:

//原始篩選法->適用於單個元素的檢驗
bool isprime_A(int n)
{
    for(int i = 2;i < sqrt(n);i++)
    {
        if(n % i == 0)
        {
            return false;
        }
    }
    return true;
}

埃氏篩法

埃氏篩法利用了一個素數的倍數一定不是素數、任何一個合數可以表示成一個素數和另一個數乘積的性質。

對於一定的範圍,先假定它們都是質數,然後從2(顯然是素數)開始,先判斷如果是素數,把它在範圍內的倍數乘積都篩去(是合數),以此類推迴圈至 sqrt(n) 即可。

程式碼如下:

//埃拉託斯特尼(Eratosthenes)篩法->適用於一定範圍的元素的篩選
bool is_prime[1000];//布林陣列來標記是否為素數
int prime[1000] = {0};    //存放素數
int q = 0;

void isprime_B(int b) //要篩選素數的區間右端點
{
    memset(is_prime,true,sizeof(is_prime));//先假設都為素數
    for(int i =
2;i <= sqrt(b);i++) { if(is_prime[i]) { prime[q++] = i; for(int j = i*2;j <= b;j += i)//素數的倍數一定不是素數 { is_prime[j] = false; } } } }

尤拉篩法

感覺尤拉篩法和埃氏篩法的原理類似…但是尤拉篩法更減少了沒有必要的計算,就是增加了處理:每一個被篩掉的數都必須是被它的最小質因子篩掉,為了保證這一點,增添了如下程式碼:

if(i % prime2[k] == 0)//確保是最小質因數
{
    break;
}

為什麼這樣檢驗,想象一下,首先篩選的前提是:

也就是因子是按照遍歷的順序,是從小到大的素數。即:

而如果不break繼續篩選的話在篩選到滿足如下性質(即上述條件)的合數後:

會繼續篩選到一個更大的質數:

也滿足篩去:

但是它也可以表示為:

但是顯然prime[j]為它的最小素數,如果它被篩去那麼它是被prime[j+x]篩去的,而這並不是它的最小質數。

所以這個條件的限制是這麼個原因大概。

程式碼如下:

//尤拉篩法->適用於一定範圍的元素的篩選,時間複雜度O(n)
bool is_prime_Euler[1000];
int prime2[1000] = {0};

void isprime_C(int b)
{
    int k = 0,j = 0;

    memset(is_prime_Euler,true,sizeof(is_prime_Euler));
    for(int i = 2;i <= b;i++)
    {
        if(is_prime_Euler[i])
        {
            prime2[j++] = i;
        }
        //接下來進行篩的操作
        while(1)
        {
            if(i*prime2[k] > b)
            {
                break;
            }
            is_prime_Euler[i*prime2[k]] = false;//最小質因數的倍數一定不是素數
            if(i % prime2[k] == 0)//確保是最小質因數
            {
                break;
            }
            k++;
        }
        k = 0;
    }
}

可能在數理層面理解的還不夠深刻…希望大家能多指點。