本页使用了标题或全文手工转换

埃拉托斯特尼筛法

维基百科,自由的百科全书
跳转至: 导航搜索

埃拉托斯特尼筛法希腊语κόσκινον Ἐρατοσθένους英语: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[编辑]

def eratosthenes(n):
    P = [i for i in range(2, n+1)]
    p = 0
    while True:
        for i in P[p + 1:]:
            if i % P[p] == 0:
                P.remove(i)
        if P[p]**2 >= P[-1]:
            break
        p += 1
    return P

if __name__ == "__main__":
    print (eratosthenes(120))

C++[编辑]

#include <vector>
#include <algorithm>//std::remove_if
#include <numeric>//std::iota

std::vector<int> eratosthenes(int max){
  std::vector<int> vi(max+1);//0, 1, 2, ..., max
  std::iota(vi.begin(), vi.end(), 0);
  if(max>=2){
    int prime=2;
    while(prime*prime<=max){//2 to sqrt(max)
      for(size_t index=prime*2; index<vi.size(); index+=prime){
        vi[index]=0;//Rule out this number.
      }
      for(prime++; prime*prime<=max; prime++){
        if(vi[prime]>0){
          break;//Jump to next non-zero.
        }
      }
    }
  }
  vi.erase(std::remove_if(vi.begin(), vi.end(), [](int i)->bool{
    return i<=1;
  }), vi.end());//Remove all zeros and the one.
  return vi;
}

参见[编辑]

註釋[编辑]

  1. ^ Nicomachus, Introduction to Arithmetic, I, 13. [1]

参考文献[编辑]

  • Κοσκινον Ερατοσθενους 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.

外部連結[编辑]