一.問題背景
對任意整數i∈[2,n],指出i為質數還是合數。
其中輸入整數n滿足2<=n<=1e6.
二.解決方案
1.樸素演算法/試除法
判斷x是否為素數,則列舉i∈[2,x-1],如果不存在i能整除x,則x為素數。
顯然,列舉量可以縮小至[2,sqrt(x)].
時間複雜度:o(n^1.5). 對於n=1e6,運算量達十億次,演算法效率不足。
2.埃氏篩法
篩法通過從大於等於2的整數集中篩除合數得到質數。
下介紹埃拉託斯特尼篩法。
定義布林型別標記陣列tag,程式結束後對於任意查詢範圍內合數x,tag[x]將為真。
演算法開始時,[2,n-1]均沒有被標記為合數。列舉i∈[2,n-1],將2i,3i,4i,… …,m⋅
\cdot
⋅i標記為合數。
對當前演算法做出如下優化:
(1)當列舉的i已經被標記為合數時,可以跳過單次迴圈,不必標記i的倍數。
(當i為合數時,i的質因數已經標記所有i的倍數)
(2)不必列舉i∈[2,n-1],只需列舉i屬於[2,sqrt(n)].
(3)對i的倍數標記時,標記i⋅
\cdot
⋅i, (i+1)⋅
\cdot
⋅i,… …,m⋅
\cdot
⋅i即可.
(當x⋅
\cdot
⋅i已經被x或x的質因數標記為合數)
給出篩函式的**。
void
eratosthenes_sieve
(int n)
3.線性篩法
重要性質:線性篩法將標記並只標記每乙個合數一次。
考慮任意合數的質因數分解p=∏
i=1m
ai
p=\prod_^ai
p=∏i=1
mai
,記a_min = min,則存在整數b滿足p = a_min ⋅
\cdot
⋅ b.
注意到p與a_min的一一對應關係,線性篩法規定p只能被a_min唯一篩除。
定義布林型別標記陣列tag,程式結束後對於任意查詢範圍內合數x,tag[x]將為真。
演算法開始時[2,n-1]均沒有被標記。列舉i∈[2,n-1],若i未標記,則判定i為質數,並將i存入動態陣列primeque中,然後進行篩除步驟:從前到後列舉j∈primeque,將j⋅
\cdot
⋅i標記為合數。
為了保證j始終為j⋅
\cdot
⋅i的最小質因數,列舉到j為i的因數時,標記j⋅
\cdot
⋅i後結束j的列舉。必然地,存在整數c∈[2,n-1],使得i=j⋅
\cdot
⋅c.倘若此時繼續列舉j』,由於j』,j∈primeque,合數j』⋅
\cdot
⋅i=j』⋅
\cdot
⋅j⋅\cdot
⋅c會被j與j多次標記,則此演算法不再具備線性篩法的重要性質。
給出篩函式的**
void
linear_sieve
(int n)
}}
由於每個合數只被標記一次,該演算法時間複雜度為o(n).
備註此部落格不採用主流標記陣列名isprime,因為初始化isprime對時間複雜度的常數影響會干涉埃氏篩法與線性篩法的時間複雜度比較。
線性(尤拉)篩法篩素數表
乙個合數可以表示成乙個素數和乙個其他數的乘積,即假設有合數a,那麼一定存在這樣的a b c,其中b和c 有乙個為素數,由此得到以下的方法,從2 maxn迴圈一遍,每次篩掉 i 與素數表每一項的乘積,最終剩下的就是素數。include include using namespace std const...
素數篩法(素數篩 線性篩)
求素數的方法在現階段可以總結為三種 這種方法最為簡單但效率太低,經過優化時間複雜度最低是o n sqrt n 輸入乙個n,輸出n以內所有素數 include intprime int n if flag 0 優化 printf d i intmain 素數篩法原理 2是素數,那麼2的所有倍數都是合數...
python利用filter生成素數
計算素數的乙個方法是埃氏篩法,它的演算法理解起來非常簡單 首先,列出從2開始的所有自然數,構造乙個序列 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,取序列的第乙個數2,它一定是素數,然後用2把序列的2的倍數篩掉 3,4,5,6,7,8,9,10,...