素數篩法


之前在解釋求素數的一道習題時,提過一個方法,叫素數篩法。下面就對這種方法的過程進行詳細的解讀。

之前提到

假設所有待判斷的數字的上限是L,聲明一個長度為L+1的布爾數組A[L+1]。用這個數組來表示對應下標的數字是不是素數。起初,將數組所有成員標記為1,然后按照某種方法將其中的非素數都標記為0即可,完成后的數組有這樣的特征:所有素數為下標的成員內存的數字都是1,所有非素數為下標的成員內存的數字都是0。例如 :2 是素數,那么A[2]=1;4不是素數,那么A[4]=0。這樣,判斷一個數是不是素數,直接查找即可。

這個標記的方法是這樣的:1不是質數,也不是合數,標記0。第二個數2是質數標記為1,而把2后面所有能被2整除的數都標記為0。2后面第一個沒划去的數是3,把3標記為1,再把3后面所有能被3整除的數都標記為0。3后面第一個沒划去的數是5,把5標記為1,再把5后面所有能被5整除的數都標記為0。這樣一直做下去,就會把不超過N的全部合數都標記為0,留下的就是不超過N的全部質數。因為希臘人是把數寫在塗臘的板上,每要划去一個數,就在上面記以小點,尋求質數的工作完畢后,這許多小點就像一個篩子,所以就把埃拉托斯特尼的方法叫做“埃拉托斯特尼篩法”,簡稱“篩法”。

當然這個方法會有重復篩掉某一合數的現象,例如,刪3的倍數時15標記為0,刪15的倍數時,同樣再一次將15標記為0。這還不夠精簡,因此有人將這個方法進行了改進:

 

首先初始A[1]=0,A[2]=1;

其次,將所有偶數下標的成員全部置為0,

接下來求出 t=√A 

接下來從i=3開始到i=t開始當A[i]=1時進行下列操作

   從 j=i*i 開始,到 j=L 結束,每次 j 加 2*i 讓A[j]=0

 

以上的改進主要是從減少重復判斷次數這個方向來進行改進的。

改進的原理如下:

1⃣️首先,將1 和 2 進行初始,1 為非素數,A[1]= 0, 2 為 素數,A[2]= 1。

2⃣️所有的偶數都是2的倍數,也就意味着,所有的偶數都能被2整除,因此所有偶數不是素數。那么將所有偶數下標的成員賦值為0是合理的。這就將素數的范圍縮小為奇數。

3⃣️為什么 i 從3 開始 到 t 便可以結束呢?原因是循環之內(黃色字體)的 j 每次是以 i * i 為初始值進行判斷的, 如果 i > t ,那么 i * i 一定 大於 L,所以 就沒必要進行 t 之后的循環了。只判斷 A[ i ]= 1(即 A[ i ]是奇數)的情況,原因是 循環之內的處理,實際上處理的是 i 的倍數是不是素數的問題,大家都清楚,不僅 2 的所有倍數是偶數,所有偶數的倍數都是偶數。

4⃣️現在解釋循環之內(黃色字體)的內容,有人很好奇,為什么不用考慮     i *3 到 i *( i-1)之間的數呢,那么假設 有一個數 p 介於 3 和( i - 1)之間, 顯然 ,如果 i * p 是小於 L 范圍之內的數, 在 i = p 的時候,就應該判斷過這個數了。

j = i * i 是非素數,這個就很明顯了。

至於為什么 j 每次的增量是 2 * i ,而不是 i 呢?因為奇數個奇數相加一定是奇數,偶數個奇數相加一定是偶數。首先 i 是 奇數,那么 i 個i 相加就可以表示為 i * i,如果增量是 i 且 i * i 是奇數的話,i * i +i 必定是偶數, i*i+2i 才是奇數,也就說增量是 i 的時候,每兩次循環中,有一次 就判斷偶數(偶數之前已經被排除過了),這樣豈不是違背了要提高效率的初衷?因此,在當前循環中需要處理的只是 奇數且是非素數的情況。j =i * i+2i=i *( i + 2)顯然也是非素數,以此類推 j = j +2*i 是非素數,直至該數超過上限結束本次循環。

這樣就保證萬無一失且不重復的排除所有情況啦。

 


 


初看這個方法,覺得好奇怪,仔細品味,回味無窮。

 

我的微信公眾號為“昵昵的寶典”,歡迎大家關注了解最新的內容。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM