素數生成算法小結


閱讀《C語言編程—一本全面的C語言入門教程》一書,看到了質數生成的小程序,特此記錄

1. 直接求解

這是最簡單和無腦的暴力算法了,直接雙重循環,復雜度為\(O(N^2)\)

void prime_generator_1(void)
{
    int p;
    int d;
    bool isPrime;

    for( p = 2; p <= MAX_NUM; ++p)
    {
        isPrime = true;

        for( d = 2; d < p; ++ d)
        {
            if(p % d == 0)
            {
                isPrime = 0;
                break;
            }
        }
        if( isPrime != false)
        {
            printf("%i ", p);
        }
    }

    printf("\n");
}

2. 一些改進

很明顯的一個改進是,任何大於2的偶數都不可能是質數,因此,在外循環中p從3開始,每次遞增2;內循環與之類似。額外注意的是,2既是偶數,也是質數,需單獨處理。

void prime_generator_2(void)
{
    int p;
    int d;
    bool isPrime;

    printf("%i ", 2);
    for( p = 3; p <= MAX_NUM; p += 2)
    {
        isPrime = true;

        for( d = 3; d < p; d += 2)
        {
            if(p % d == 0)
            {
                isPrime = 0;
                break;
            }
        }
        if( isPrime != false)
        {
            printf("%i ", p);
        }
    }

    printf("\n");
}

3. 繼續改進

以上的改進雖然有效,但算法的效率並沒有根本性的提高,特別是在產生大型的質數表(>1,000,000),算法的效率至關重要。

有兩個標准可以幫助提高效率

  • 任何一個非質整數都可以分解為多個質數的乘積,也就是說,如果一個數不能被任何質數整除,那么這個數就是一個質數。
  • 任何一個非質數的整數,肯定會有一個小於其平方根的質因數。
void prime_generator_3(void)
{
    int primes[MAX_NUM];
    int primeIndex = 2;
    bool isPrime;

    primes[0] = 2;
    primes[1] = 3;

    for( int p = 5; p <= MAX_NUM; p += 2)
    {
        isPrime = true;

        for( int i = 1; isPrime && primes[i] <= sqrt(p); ++i)
        {
            if(p % primes[i] == 0)
            {
                isPrime = false;
                break;
            }
        }
        if( isPrime == true)
        {
            primes[primeIndex ++] = p;
        }
    }

    for(int i = 0; i < primeIndex; ++ i)
    {
        printf("%i ", primes[i]);
    }
    printf("\n");
}

4. 埃拉托色尼篩網法

其步驟為:

  1. 定義整數數組P, 將所有的數組元素設置為0.
  2. 設置變量i等於2。
  3. 如果i > n,算法結束。
  4. 如果P[i]等於0, 那么i是一個質數。
  5. 對於所有的正整數j, 如果i * j <= n,將數組元素P[i*j]設置為1。
  6. i的值增加1,返回第3步。

代碼如下:

void prime_generator_4(void)
{
    int primes[MAX_NUM + 1] ={0};
    int i = 2;

    while(i <= MAX_NUM)
    {
        if(primes[i] == 0)
        {
            printf("%i ", i);
        }
        for( int j = 2; i * j <= MAX_NUM; ++j)
        {
            primes[i * j] = 1;
        }
        ++i;
    }
    printf("\n");
}

5. 對比

MAX_NUM =500000 時,前三種算法的計算時長分別為:

可以看到,經過改進,算法的時間消耗得到大幅降低,表明改進算法的有效性。

6. 關於數組越界帶來的死循環問題

這個問題在第4部分代碼編寫過程中出現過,后來經過搜索找到了原因,數組越界導致循環變量被重新賦值。其匯編代碼如下:

在此驗證了一個簡單的C語言數組循環語句,對循環變量和數組越界元素的地址進行了輸出,可以看到,二者地址一致,證明了以上的論斷。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM