本頁使用了標題或全文手工轉換

埃拉托斯特尼篩法

維基百科,自由的百科全書
前往: 導覽搜尋

埃拉托斯特尼篩法(希臘語:κόσκινον Ἐρατοσθένους英語:sieve of Eratosthenes ),簡稱埃氏篩,也有人稱質數篩。這是一種簡單且歷史悠久的篩法,用來找出一定範圍內所有的質數
所使用的原理是從2開始,將每個質數的各個倍數,標記成合數。一個質數的各個倍數,是一個差為此質數本身的等差數列。此為這個篩法和試除法不同的關鍵之處,後者是以質數來測試每個待測數能否被整除。
埃拉托斯特尼篩法是列出所有小質數最有效的方法之一,其名字來自於古希臘數學家埃拉托斯特尼,並且被描述在尼科馬庫斯所著Introduction to Arithmetic中。[1]

算式[編輯]

給出要篩數值的範圍n,找出以內的質數。先用2去篩,即把2留下,把2的倍數剔除掉;再用下一個質數,也就是3篩,把3留下,把3的倍數剔除掉;接下去用下一個質數5篩,把5留下,把5的倍數剔除掉;不斷重複下去......。

步驟[編輯]

埃拉托斯特尼篩法

詳細列出算法如下:

  1. 列出2以後的所有序列:
    • 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
  2. 標出序列中的第一個質數,也就是2,序列變成:
    • 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
  3. 將剩下序列中,劃摽2的倍數(用紅色標出),序列變成:
    • 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
  4. 如果現在這個序列中最大數小於最後一個標出的質數的平方,那麼剩下的序列中所有的數都是質數,否則回到第二步。

  1. 本例中,因為25大於2的平方,我們返回第二步:
  2. 剩下的序列中第一個質數是3,將主序列中3的倍數劃出(紅色),主序列變成:
    • 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
  1. 我們得到的質數有:2,3
  2. 25仍然大於3的平方,所以我們還要返回第二步:
  3. 現在序列中第一個質數是5,同樣將序列中5的倍數劃出,主序列成了:
    • 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
  4. 我們得到的質數有:2, 3, 5 。
  5. 因為25等於5的平方,結束循環

結論:去掉紅色的數字,2到25之間的質數是:2, 3, 5, 7, 11, 13, 17, 19, 23。

演算法[編輯]

埃拉托斯特尼篩法,可以用以下的虛擬碼來表示:

Input: an integer n > 1
 
Let A be an array of Boolean values, indexed by integers 2 to n,
initially all set to true.
 
 for i = 2, 3, 4, ..., not exceeding n:
  if A[i] is true:
    for j = i2, i2+i, i2+2i, i2+3i, ..., not exceeding n :
      A[j] := false
 
Output: all i such that A[i] is true.

以上演算法可以得到小於等於n的所有質數,它的複雜度是O(n log log n)

程式代碼[編輯]

Python 3.6[編輯]

 1 def eratosthenes(n):
 2     P = [i for i in range(2, n+1)]
 3     p = 0
 4     while True:
 5         if P[p]**2 > P[-1]:
 6             break
 7         for i in P[p + 1:]:
 8             if i % P[p] == 0:
 9                 P.remove(i)
10         p += 1
11     return P
12 
13 if __name__ == "__main__":
14     print (eratosthenes(120))

C++[編輯]

 1 bool a[MAXN];
 2 void erat(int maxn)
 3 {
 4 	a[0]=1;
 5 	a[1]=1;
 6 	for(int i=2;i<=maxn;++i)
 7 	{
 8 		if(!a[i])
 9 		{
10 			for(int j=2*i;j<=maxn;j+=i)
11 			{
12 				a[j]=1;
13 			}
14 		}
15 	}
16 }

歐拉篩法[編輯]

歐拉篩法(Sieve of Euler)是埃拉托斯特尼篩法的一種改進有人稱其為快速線性篩法。回顧經典的埃拉托斯特尼篩法,它可能對同一個質數篩去多次,故時間複雜度為O(n log log n)。如果用某種方法使得每個合數只被篩去一次就變成是線性的了。不妨規定每個合數只用其最小的一個質因數去篩,這便是歐拉篩了,時間複雜度 O(n).

代碼實現[編輯]

 1 #include<iostream>
 2 using namespace std;    
 3 const long N = 200000;   
 4 long prime[N] = {0},num_prime = 0;    
 5 int isNotPrime[N] = {1, 1};   
 6 int main()    
 7 {     
 8      	for(long i = 2 ; i < N ; i ++)       
 9        	{            
10 	    	if(! isNotPrime[i])               
11 	 	    	prime[num_prime ++]=i;  
12 	    	//关键处1        
13 	    	for(long j = 0 ; j < num_prime && i * prime[j] <  N ; j ++)
14     		{               
15 		      	isNotPrime[i * prime[j]] = 1;  
16 	  	    	if( !(i % prime[j] ) )  //关键处2                  
17 		    		break;           
18 	    	}        
19     	}        
20 	return 0;   
21 }

代碼解釋[編輯]

首先,先明確一個條件,任何合數都能表示成一系列質數的積。

不管 i 是否是質數,都會執行到「關鍵處1」,

①如果 i 都是是質數的話,那簡單,一個大的質數 i 乘以不大於 i 的質數,這樣篩除的數跟之前的是不會重複的。篩出的數都是 N=p1*p2的形式, p1,p2之間不相等

②如果 i 是合數,此時 i 可以表示成遞增質數相乘 i=p1*p2*...*pn, pi都是質數(2<=i<=n),  pi<=pj  ( i<=j )

p1是最小的係數。

根據「關鍵處2」的定義,當p1==prime[j] 的時候,篩除就終止了,也就是說,只能篩出不大於p1的質數*i。

我們可以直觀地舉個例子。i=2*3*5

此時能篩除 2*i ,不能篩除 3*i

如果能篩除3*i 的話,當 i' 等於 i'=3*3*5 時,篩除2*i' 就和前面重複了。[2]

簡單證明[編輯]

這個看似很簡單, 其實還是要注意一下細節的. 搞清了證明其他的問題也就清楚了.

證明分兩部分. 首先證每個合數都會被篩到 (正確性), 其次證每個合數只會被篩到一次 (複雜度).

每個合數都會被篩到

設有一合數(為質數),

則一定會在 時被篩去(此時),因為對於小於的質數, 一定不會被整除.

每個合數都只會被篩到一次

與上面一樣, 還是設有一合數(為質數)

倘若存在一個質因子也篩去了 , 那麼此時 .

  • 此時在內層循環中已經早早地 break 掉了, 因為
  • 此時  還沒加進質數表 (順便一提: 這種情況只有 可能 在  時發生)[3]

難以理解的地方[編輯]

為何不把 i % primes[j] == 0 放在前面?[編輯]

放前面的話, 所有的「某個質因子的次數不為1」的合數便會被當成質數. 至於為什麼, 請看證明.

為何沒有 j < totPrimes ?[編輯]

  • 當為質數時, 內層循環會在最後一個質數 (也就是  自己) 終止
  • 當為合數時, 內層循環會在它的第一個質因數終止

當然加了也沒有問題.[3]

參見[編輯]

參考文獻[編輯]

  1. ^ Nicomachus, Introduction to Arithmetic, I, 13. [1]
  2. ^ 一般篩法求素數+快速線性篩法求素數 - CSDN博客. blog.csdn.net. [2018-02-20]. 
  3. ^ 3.0 3.1 __debug. 篩法小結 (Eratosthenes/Euler). __debug's Home. 2015-09-29 [2018-02-20] (英語). 
  • Κοσκινον Ερατοσθενους or, The Sieve of Eratosthenes. Being an Account of His Method of Finding All the Prime Numbers, by the Rev. Samuel Horsley, F. R. S., Philosophical Transactions (1683-1775), Vol. 62. (1772), pp. 327-347.

拓展閱讀[編輯]