埃氏篩法的詳解

埃氏篩法

一個判斷素數的高效算法

關於埃氏篩法的百度百科解釋在這裏埃拉託斯特尼篩法,當然我不可能給個百度百科的解釋就撤,那會被打死的。
衆所周知,素數指的是除了1和它本身之外沒有其它約數的數
我們假定一個數num,那麼如果我們想通過編程來判斷它是不是素數,我們首先通過它的定義想到暴力枚舉方法,即用for循環配合取模操作實現,c++代碼如下

bool flag = true; // flag作爲標誌來標識這個數是不是素數,默認設置爲true
for(int i=2;i<num/2;i++)
{
    if(num % i == 0)
    {
        flag = false; // 如果能被整除了,那就不是素數,退出循環
        break;
    }
}
if(flag)
{
    cout<<"數:"<<num<<"是素數"<<endl;
}

當然這種方法就顯得很麻煩,雖然直觀易懂,但是時間複雜度達到了n^2級。
當然如果稍微改進一點的話就會知道把我上面的代碼循環中的i < num/2改成i*i < num,時間可以縮短。但是仍不夠明顯。


快樂的分割線


下面我們開始埃氏篩法的學習

看過上圖百度百科的同學應該明白,埃氏篩法是範圍判斷素數的方法,即,你給出一個數n,我用埃氏篩法能判斷從1-n的所有素數出來。

原理

素數的倍數肯定不是素數

給定一個數n,我們開一個大小爲n+1的bool型數組,即 bool nums[n+1] ,並全部初始化爲false, 在這裏聲明一點,這個數組的 nums[0] 與 nums[1] 我們並不會使用到。
建立了這樣一個數組之後,我們就可以直接開幹啦,我們首先要找到最小的素數,即2,從而開始循環開炮
OK非常棒,現在我們已經能找出素數中的最小者了,任務完成一半!
接下來,我們應用我們的原理——素數的倍數肯定不是素數
這裏有張表

是否是素數
2
3
4 不是(通過素數2的倍數判斷)
5
6 不是(通過素數2,3的倍數判斷)
7
8 不是(通過素數2的倍數判斷)
9 不是(通過素數3的倍數判斷)
加入我們要求10以內的素數,開一個nums[11],然後定位找到最小的素數->2,以2爲基點,開炮,把2的倍數全部打死,當然這個也是有範圍的,2的倍數我們只要判斷到小於n就可以了,即小於10。然後2的倍數打死完了,再找倖存的最小素數3,以3爲基點,開炮,在3的炮火攻擊下,上次僥倖存活的9被揪出來打死了。***我們會一直判斷,直到我們的基點達到一個臨界點——小於等於n的開根號,這樣我們就把所有潛藏的合數敵人全部消滅了,不信你瞅瞅? ***

原理如此,接下來附上這一部分的代碼,看完代碼之後我會有一個小小的問題遺留給大家思考

int main() // 這裏只給出實現代碼了,上面的頭文件什麼的都沒寫了
{
    int num;
    cin >> num;
    bool* nums = new bool[num];   // 這裏我們如果需要用變量創建數組的話必須這樣創建喔!
    for (int i = 0; i < num; i++)
    {
        nums[i] = true;
    }
    int sn = sqrt(num);
    for (int i = 2; i <= sn; i++) /* 從最小的素數2開始開炮*/
    {
        if (nums[i])
        {
            for (int j = i * i; j < num; j+=i)  // 此處需要注意,我們開炮的時候,第一顆炮彈直接打到i的平方上,這是避免了重複判斷,j每次要增長i
            {
                nums[j] = false;   // 跟我一起,開炮!!
            }
        }
    }
    for (int i = 2; i < num; i++)
    {
        if (nums[i])
        {
            cout << i << "\t";  // 打印出選出來的素數你看看,這裏我喜歡用製表符,個人習慣,看着舒服
        }
    }

    delete []nums;  // 最後可別忘了釋放指針內存哦,並且將指針置空,養成好習慣,不要野指針!
    nums = nullptr;
    return 0;
}

好了,代碼部分結束,最後我還遺留一個問題,你們有沒有發現,我們這裏重複判斷了?比如我已經判斷12是偶數了,已經殺死了,但是我以3爲基點開炮的時候,還是會再打它一次,炸屍,這會不會浪費我們的炮彈資源(時間)呢?該如何改進這個問題呢?思考一下?

謝謝你來看我!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章