判斷數n是否為乙個素數,基本方法為從2開始向後列舉,若n不能被2,3,4,…,n-1整除,則n為素數,該判斷方法的時間複雜度為o(n
)o(n)
o(n)
;更快的方法為,當列舉至n
\sqrt n
n時即可判斷是否為素數,該判斷方法的時間複雜度為o(n
)o(\sqrt n)
o(n)。
**如下:
//寫法1,其中sqrt函式位於標頭檔案,double sqrt(double a)
bool
isprime
(int n)
return
true;}
//寫法2,當n不接近int型上界時;或i以被定義為long long型別,不至於溢位
bool
isprime
(int n)
return
true
;}
!!!注意溢位問題。
對1~n依次判斷是否為素數,其列舉部分複雜度為o(n
)o(n)
o(n)
,判斷是否為素數部分為o(n
)o(\sqrt n)
o(n
),因此總複雜度為o(n
n)
o(n\sqrt n)
o(nn)
。當資料量小於105
10^5
105時,該演算法可行。
**如下:
cosnt int maxn =
101;
//表長
int prime[maxn]
, pnum =0;
//prime陣列存放所有素數,pnum為素數個數
bool p[maxn]=;
//p[i] == true表示i為素數
void
find_prime()
}}
對每個素數,劃去其所有倍數,剩下的即為素數。時間複雜度為o(n
logl
ogn)
o(nloglogn)
o(nlog
logn
)。當資料量小於107
10^7
107時可行,達到107
10^7
107附近的難以滿足。
舉例如下:對2~15進行判斷
**如下:
cosnt int maxn =
101;
//表長
int prime[maxn]
, pnum =0;
//prime陣列存放所有素數,pnum為素數個數
bool p[maxn]=;
//如果i為素數,則p[i] = false,否則為true
void
find_prime()
}}
注:優化,倍數的篩去從j=i
∗i
j=i*i
j=i∗
i開始,而不是i+i
i+ii+
i開始,因為i∗(
2至i−
1)
i*(2至i-1)
i∗(2至i
−1)在篩查2~i−1
i-1i−
1的倍數時已經被篩去。
提出背景:由於埃氏篩法在劃去倍數的過程中對於乙個合數可能進行了多次重複劃去,如對於合數30,當划去2,3,5倍數時均對其進行了操作,帶來了不必要的重複,進而導致複雜度上公升。
主要思想:為避免合數的重複篩查,對每個數,使其被它的最小質因數篩查掉(最小質因數具有唯一性)。
時間複雜度為o(n
)o(n)
o(n)
;當資料量小於108
10^8
108時合適。
**如下:
const
int maxn =
101;
//表長
int prime[maxn]
, pnum =0;
//prime陣列存放所有素數,pnum為素數個數
bool p[maxn]=;
//如果i為素數,則p[i] = false,否則為true
void
find_prime()
for(
int j =0;
(j < maxn)
&&(i * prime[j]
< maxn)
; j++)}
}
一些問題:
[1]. 《演算法筆記》p160-162
[2]. 數論_尤拉篩法
素數篩法 埃氏篩及尤拉篩
在做題中會經常遇到有關素數的問題,整理一下學過的兩種素數篩法。時間複雜度 o nloglogn 我們知道乙個素數的倍數肯定是乙個合數,乙個合數可以由多個素數相乘得到,所以可以從2開始把2的倍數篩一遍,找到下個素數在篩一遍。篩完後素數的倍數都被篩掉了,剩下的就是素數。如下 const int n 1e...
線性篩法求素數(埃氏篩法 尤拉篩法)
篩法都是初始化把所有數都先設為素數,然後篩除合數。理解起來比較簡單,就是從小到大的列舉每乙個數,標記它的所有倍數都是合數 非素數 放到u i 為false,u中的下標對應的就是這個數的值。bool u maxn int num,su maxn 1.埃氏篩法 void prime 從小到大的篩選素數,...
埃氏篩法與尤拉篩法
給定整數n,請問n以內有多少個素數?摘自挑戰程式程式設計。要列舉n以內素數,可以用埃氏篩法。這是乙個與輾轉相除法一樣古老的演算法。首先,將2到n範圍內的所有整數寫下來。其中最小的數字2是素數。將表中所有2的倍數都劃去。表中剩餘的最小數字是3,它不能被更小的數整除,所以是素數。在將表中所有3的倍數都劃...