埃氏篩 尤拉篩

2022-09-12 03:30:16 字數 2990 閱讀 6375

對於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的倍數都劃...