1. 程式人生 > >素數篩選法講解

素數篩選法講解

當一個數不算大的時候,可以用普通的求素數的方法去求,但是如果一個數過大的話,就像讓求1~1000000000之間素數的個數,普通方法就不行了,這時候就需要用到素數篩選法,它的時間複雜度是O(n),儘管不算很好,但是,也算是目前為止比較快的一種方法了,它是以空間換取時間,現在的計算機,空間有的是,但是時間是非常珍貴的。

效率問題特別重要。他的原理就是標記,防止重複判斷,這樣提高了效率。就像2是素數,所有是2的倍數的肯定都不是素數,這時候標記上,接著判斷3是素數,所有是3的倍數的都肯定不是素數,這時就要標記上,以此下去,執行到根下(總數),這樣就會得到一個素數表,所有沒有被標記的都是素數,下面是具體的程式碼實現,程式碼裡面有註釋。寫的很清楚。

先來看看普通的求素數方法:

void Getprime()
{
    prime[0] = prime[1] = false;
    prime[2] = true;
    for(int i = 2; i < MAX; i++)
    {
        bool flag = true;
        for(int j = 2; j <= sqrt(i); j++) //從2判斷到sqrt(i),如果i % j == 0,則i不是素數
        {
            if(i % j == 0)
            {
                flag = false;
                break;
            }
        }
        if(flag)//不是素數就標記成false
            prime[i] = true;
        else
            prime[i] = false;
    }
}

它的執行時間是非常長的,所以這時候就要引出素篩的演算法:

void Getprime()
{
    memset(prime, true, sizeof(prime));//初始化,將prime陣列全部都初始化為true
    prime[0] = prime[1] = false;
    prime[2] = true;
    for(ll i = 2; i * i <= MAX; i ++)//從2開始遍歷,i * i <= MAX 就等價於 i < sqrt(MAX);但是前者更不容易出錯
    {
        if(prime[i])//如果沒有被標記的話將它的倍數的數標記(標記就是將它賦值為false)
        {
            for(ll j = i + i; j <= MAX; j += i)//因為是從2開始的,所以j = i * i 就行了,最小的一個他的倍數的就是i * i了,不可能有比這個更小的了
                prime[j] = false;//標記為false
        }
    }
}

素篩的程式碼比較短,而且執行速度很快,是用了空間換了時間,不過現在來說,時間更加重要一些,所以素篩還是被廣泛運用的。

OVER!