對於1~n範圍內素數的查詢,我們常用的二重迴圈暴力演算法的複雜度是o(n2),如果利用開根縮小範圍的時間複雜度也無非是在o(n
nn\sqrt n
nn),而,這些演算法對於n在105以內都是可以接受的,但是如果需要更大範圍的素數表,這些演算法將顯得力不從心。下面將介紹更加高效的演算法。
埃氏篩也叫素數篩法,其關鍵在乙個「篩」字。演算法從小到大列舉所有數,對於每乙個素數,篩去它的所有倍數,剩下的就都是素數了。埃氏篩的時間複雜度只有o(n
log
log
nn\log \log n
nlog
logn
)。下面是乙個例子:求1~15中的所有素數。(高亮的是已經篩去的)
2是素數(唯一需要事先確定的),因此篩去所有2的倍數,即4、6、8、10、12、14。
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
3沒有被前面的步驟篩去,因此3是素數,篩去所有3的倍數,即6,9,12,15
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
4已經被篩去,因此4不是素數。
5沒有被前面的步驟篩去,因此5是素數,篩去所有5的倍數,即10,15
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
6已經被篩去,因此6不是素數。
7沒有被前面的步驟篩去,因此7是素數,篩去所有7的倍數 ,即14
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
8已經被篩去,因此8不是素數。
9已經被篩去,因此9不是素數.
10已經被篩去,因此10不是素數.
11沒有被前面的步驟篩去,因此11素數,但15以內沒有11的倍數。
12已經被篩去,因此12不是素數.
13沒有被前面的步驟篩去,因此13素數,但15以內沒有13的倍數。
14已經被篩去,因此14不是素數.
15已經被篩去,因此15不是素數.
至此,1~15以內的所有素數已全部得到,即2、3、5、7、11、13。
由這個例子很形象的展示了埃氏篩的過程,那麼接下來就直接上**:
int prime[maxn]
,pnum =0;
//prime陣列存放所有素數,pnum為素數的個數
bool p[maxn]=;
//如果i為素數,則p[i]為false;否則為true
void
find_prime()
}}}
而分析埃氏篩我們會發現,埃氏篩在執行過程中會有多個數被重複篩選過了,只要避免這些重複篩選,我們的演算法將會再次提高效率,這就出現了尤拉篩。
尤拉篩法的基本思想 :在埃氏篩法的基礎上,讓每個合數只被它的最小質因子篩選一次,以達到不重複的目的。尤拉篩的時間複雜度僅為o(n)。
先上**:
int prime[maxn]
,pnum =0;
//prime陣列存放所有素數,pnum為素數的個數
bool p[maxn]=;
//如果i為素數,則p[i]為false;否則為true
void
find_prime()
}}
再以舉前面那個例子:求1~15中的所有素數。(高亮的是已經篩去的)
2是素數(唯一需要事先確定的),此時pnum = 1,i = 2;
j = 1, i*prime[j] = 4
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
3沒有被前面的步驟篩去,因此3是素數,此時pnum = 2,i = 3;
j = 1, i*prime[j] = 6
j = 2, i*prime[j] = 9
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
4已經被篩去,因此4不是素數,此時pnum = 2,i = 4;
j = 1, i*prime[j] = 8
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
5沒有被前面的步驟篩去,因此5是素數,此時pnum = 3,i = 5;
j = 1, i*prime[j] = 10
j = 2, i*prime[j] = 15
j = 3, i*prime[j] = 25 (>15)
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
6已經被篩去,因此6不是素數,此時pnum = 3,i = 6。
j = 1, i*prime[j] = 12
j = 2, i*prime[j] = 18 (>15)
j = 3, i*prime[j] = 30 (>15)
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
7沒有被前面的步驟篩去,因此7是素數,此時pnum = 3,i = 7。
j = 1, i*prime[j] = 14
j = 2, i*prime[j] = 21 (>15)
j = 3, i*prime[j] = 35 (>15)
j = 4, i*prime[j] = 49 (>15)
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
此後的i*prime[1]>15,因此不必繼續判斷了。至此,1~15以內的所有素數已全部得到,即2、3、5、7、11、13。
首先,尤拉篩的過程中有兩個值得我們關注的點:
p[i*prime[j]] = true:這裡不是用i的倍數來消去合數,而是把 prime裡面紀錄的素數,公升序來當做要消去合數的最小素因子。
尤其注意的是if(i%prime[j]==0) break;
這段**:
當i為prime[j]的倍數時要跳出迴圈,因為:當i = k * prime[j],如果繼續j+1,則會有 i * prime[j+1] = prime[i] * k * prime[j+1],而當i迴圈到i = k * prime[j+1]時會重複篩選,因此這裡提前結束。
埃氏篩 線性 尤拉 篩
埃氏篩 簡單,暴力。int isprime 50000 void getlist int size 看似簡單,但不真搞明白這個,無法學會線性 尤拉 篩。關鍵在於如何去做的合數,用了兩個引數,乙個是質數,即 prime i 另乙個是質數的倍數,即 j 相乘得到合數。線性篩 埃氏篩的改良版,使乙個合數只...
素數篩法 埃氏篩及尤拉篩
在做題中會經常遇到有關素數的問題,整理一下學過的兩種素數篩法。時間複雜度 o nloglogn 我們知道乙個素數的倍數肯定是乙個合數,乙個合數可以由多個素數相乘得到,所以可以從2開始把2的倍數篩一遍,找到下個素數在篩一遍。篩完後素數的倍數都被篩掉了,剩下的就是素數。如下 const int n 1e...
埃氏篩法與尤拉篩法
給定整數n,請問n以內有多少個素數?摘自挑戰程式程式設計。要列舉n以內素數,可以用埃氏篩法。這是乙個與輾轉相除法一樣古老的演算法。首先,將2到n範圍內的所有整數寫下來。其中最小的數字2是素數。將表中所有2的倍數都劃去。表中剩餘的最小數字是3,它不能被更小的數整除,所以是素數。在將表中所有3的倍數都劃...