線性篩選素數

2021-09-12 09:48:34 字數 2165 閱讀 8959

侵刪。。。

**題目:給出乙個正整數n,列印出所有從1~n的素數(即質數);

關鍵是要找出乙個判斷乙個正整數n是否為素數的方法…

傻瓜解法–n,n/2

1 #include2 int main()

3 12 }

這裡迴圈取到sqrt(n),效率改進不少了…但顯然還是不夠理想….繼續往下看

普通篩選法–埃拉託斯特尼篩法

先簡單說一下原理:

基本思想:素數的倍數一定不是素數

實現方法:用乙個長度為n+1的陣列儲存資訊(0表示素數,1表示非素數),先假設所有的數都是素數(初始化為0),從第乙個素數2開始,把2的倍數都標記為非素數(置為1),一直到大於n;然後進行下一趟,找到2後面的下乙個素數3,進行同樣的處理,直到最後,陣列中依然為0的數即為素數。

說明:整數1特殊處理即可。

舉個例子,n=20時,演示如下圖:

最後陣列裡面還是0的就是素數了…

**實現如下:

prime用來儲存得到的素數 prime = tot 是當前得到的素數的個數 check :0表示是素數  1表示合數

1 memset(check, 0, sizeof(check));

2 int tot = 0;

3 for (int i = 2; i <= n; ++i)

4 9 for (int j = i+i; j <= n; j += i)

10

13 }

此篩選法的時間複雜度是o(nloglogn) 空間複雜度是o(n)

不足之處也比較明顯,手動模擬一遍就會發現,很多數被處理了不止1遍,比如6,在素數為2的時候處理1次,為3時候又標記一次,因此又造成了比較大的不必要處理…那有沒有改進的辦法呢…就是下面改進之後的篩法…

線性篩法–尤拉篩法

先上**吧…

1 #include2 #include3 #define maxn 100005

4 #define maxl 1299710

5 int prime[maxn];

6 int check[maxl];

7 8 int tot = 0;

9 memset(check, 0, sizeof(check));

10 for (int i = 2; i < maxl; ++i)

11 16 for (int j = 0; j < tot; ++j)

17

22 check[i*prime[j]] = 1;

23 if (i % prime[j] == 0)

24

27 }

28 }

精華就在於紅色標註那兩處,它們保證每個合數只會被它的最小質因數篩去,因此每個數隻會被標記一次,所以時間複雜度是o(n)

還是按上面的例子進行一遍模擬:n=20

此過程中保證了兩點:

1、合數一定被乾掉了…

2、每個數都沒有被重複地刪掉

(證明 見參考資料)

引申–求尤拉函式

在數論,對正整數n,尤拉函式是小於或等於n的數中與n互質的數的數目。此函式以其首名研究者尤拉命名,它又稱為euler』s totient function、φ函式、尤拉商數等。 例如φ(8)=4,因為1,3,5,7均和8互質。

求尤拉函式的方法只需在上面的程式中稍有改動即可,此處只貼出**:

按 ctrl+c 複製**

按 ctrl+c 複製**

若是素數,那麼從1~n-1都是和它互質的數,所以phi(i) = i - 1;

另外兩個是積性函式(見參考資料)的公式和尤拉函式的特性。

參考資料

1、2、

3、posted @

2018-07-30 15:06

大眼俠 閱讀(

...)

編輯收藏

素數線性篩選

include include includeusing namespace std bool isprime 10000001 int pri 2000001 prin int findprime int maxn for int j 0 jmaxn break 當過大了就跳出 isprime i...

素數的線性篩選

出處 線性篩選法之所以稱之為線性就是因為其對於每乙個合數只用其最小的素因子將其篩選出來。如下 include include include define maxn 1000000 using namespace std int p 1000005 pri 1000005 idx 1 void ge...

線性篩選素數法

pri 1到pri n遞增,composite num1 n 在遍歷 1,n 的數時,剛好maxdivisor1 pri 3 pri 4 pri n 1 pri n。pri 1是是它最小的質因數。maxdivisor如果乘以乙個大於pri 3的質因數,例如pri 4,就找到另乙個合數 composi...