埃拉托斯特尼筛法

埃拉托斯特尼筛法古希臘語κόσκινον Ἐρατοσθένους,英語:sieve of Eratosthenes),簡稱埃氏筛,是一种用來生成英语Generating primes質數筛法,得名於古希臘數學家埃拉托斯特尼。其基本步骤是從最小的質數2開始,將该質數的所有倍數標記成合數,而下一个尚未被标记的最小自然数3即是下一个質數。如此重复这一过程,将各个质数的倍数标记为合数并找出下一个质数,最终便可找出一定範圍內所有質數。

埃拉托斯特尼筛法可能在埃拉托斯特尼的时代之前就已经为人所知[1]:14,并记载于另一位古希腊数学家尼科马库斯的《算术概论英语Introduction to Arithmetic》中,尽管该著作中的这一筛法是从3开始,从奇数中依次筛去奇数的倍数,而非从自然数中筛去质数的倍数[2]:242-243

使用埃拉托斯特尼筛法找出120以内的所有質數。由于112=121>120,当11成为最小的未标记整数时,尚未标记的所有数皆可确认为質數。请注意到在标记时直接从每个质数的平方开始。

运用与示例[编辑]

埃拉托斯特尼筛法通过不断地标记当前质数的所有倍数为合数,从而取得最小的未标记整数为下一个質數。不过,在实际使用此筛法寻找一个范围内的質數时,不需要检查范围内所有整数,也不需要对每个質數都标记其所有的倍数。

  1. 寻找以内的質數时,若找到了一个大于的质数,则剩余的所有尚未标记的数也都是質數。
    证明:若这些尚未标记的数中有任意一个为合数,设之为,则必定是除1与自身以外的两个因数的乘积。但既然尚未被标记,则所有小于等于的数均不是的因数。故这两个因数必然都大于,则不可能在以内[3]:103-104[4]:4
  2. 标记某一質數的倍数时,不需要每次皆从开始,而可直接从开始标记。
    证明:所有较更小的的倍数必然拥有一个更小的质数为其因数,故在标记之前的质数的倍数时它们已经被标记过了[5]

若要找出25以内的所有质数,使用如上述改进过的埃拉托斯特尼筛法的具体过程如下:

  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,由22=4开始划去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. 记录下一質数3,由32=9开始划去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
  4. 记录下一質数5,由52=25开始划去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
  5. 下一質数为7,而72=49>25,故剩余所有未标记的数皆为質数:
    2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

由此得到25內的質数为2,3,5,7,11,13,17,19,23。

以上的算法可用以下伪代码表示:

输入:整数n > 1   设A为布尔值矩阵,下标是2至n的整数, 初始时全部设成true。    for i = 2, 3, 4, ..., 不超过if A[i]为truefor j = i2, i2+i, i2+2i, i2+3i, ..., 不超过nA[j] := false   输出:使A[i]为true的所有i

埃拉托斯特尼筛法的时间复杂度;相比之下,若是通过对范围内每个整数进行试除法来找出范围内的质数,则其时间复杂度为[1]:13-14[5]

程式码[编辑]

Python 3.6-3.10[编辑]

def eratosthenes(n):     is_prime = [True] * (n + 1)     for i in range(2, int(n ** 0.5) + 1):         if is_prime[i]:             for j in range(i * i, n + 1, i):                 is_prime[j] = False     return [x for x in range(2, n + 1) if is_prime[x]] print(eratosthenes(120)) 

C語言[编辑]

int prime[100005]; bool is_prime[1000005];  int eratosthenes(int n) {     int p = 0;     for (int i = 0; i <= n; i++) {         is_prime[i] = true;     }     is_prime[0] = is_prime[1] = 0;     for (int i = 2; i <= n; i++) {         if (is_prime[i]) {             prime[p++] = i;             if (1ll * i * i <= n) {                 for (int j = i * i; j <= n; j += i) {                     is_prime[j] = 0;                 }             }         }     }     return p; } 

C語言新版

#include <stdio.h> #include <stdlib.h>  /* N: positive integer    verbose: 1 -- print all prime numbers < N, 0 -- no print    return total number of prime numbers < N.     return -1 when there is not enough memory. */ int eratosthenesSieve(unsigned long long int N, int verbose) {   // prime numbers are positive, better to use largest unsiged integer   unsigned long long int i, j, total; // total: number of prime numbers < N   _Bool *a = malloc(sizeof(_Bool) * N);    if (a == NULL) {     printf("No enough memory.\n");     return -1;   }      /* a[i] equals 1: i is prime number.      a[i] equals 0: i is not prime number.      From beginning, set i as prime number. Later filter out non-prime numbers   */   for (i = 2; i < N; i++) {     a[i] = 1;    }    // mark multiples(<N) of i as non-prime numbers   for (i = 2; i < N; i++) {     if (a[i]) { // a[i] is prime number at this point       for (j = i; j < (N / i) + 1; j++) { 	/* mark all multiple of 2 * 2, 2 * 3, as non-prime numbers; 	   do the same for 3,4,5,... 2*3 is filter out when i is 2 	   so when i is 3, we only start at 3 * 3 	*/ 	a[i * j] = 0;       }     }   }    // count total. print prime numbers < N if needed.   total = 0;   for (i = 2; i < N; i++) {     if (a[i]) { // i is prime number       if (verbose) { 	printf("%llu\n", i);       }       total += 1;     }   }    return total; }  int main() {   unsigned long long int a1 = 0, a2 = 0, N = 10000000;      a1 = eratosthenesSieve(N, 1); // print the prime numbers   printf("Total of prime numbers less than %llu is : %llu\n", N, a1);      a2 = eratosthenesSieve(N, 0); // not print the prime numbers   printf("Total of prime numbers less than %llu is : %llu\n", N, a2);      return 0; } 

C++[编辑]

#include <vector>  auto eratosthenes(int upperbound) {   std::vector<bool> flag(upperbound + 1, true);   flag[0] = flag[1] = false; //exclude 0 and 1   for (int i = 2; i * i <= upperbound; ++i) {     if (flag[i]) {       for (int j = i * i; j <= upperbound; j += i)         flag[j] = false;     }   }	   return flag; } 

R[编辑]

eratosthenes <- function(n) {   if (n == 1) return(NULL)   if (n == 2 | n == 3) return(2:n)   numbers <- 2:n   primes <- rep(TRUE, n-1)   for (i in 2:floor(sqrt(n))) {     if (primes[i-1]) {       for (j in seq(i * i, n, i))         primes[j-1] <- FALSE     }   }   return(numbers[primes]) } 

JavaScript[编辑]

const countPrimes = function (n) {   const isPrime = new Array(n).fill(true);    for (let i = 2; i <= Math.sqrt(n); i++) {     if (isPrime[i]) {       for (let j = i * i; j <= n; j += i) {         isPrime[j] = false;       }     }   }    let count = 0;   for (let i = 2; i < n; i++) {     if (isPrime[i]) {       count++;     }   }    return count; }; 

参见[编辑]

参考文献[编辑]

  1. ^ 1.0 1.1 Stefan Hougardy; Jens Vygen. Algorithmic Mathematics. Cham: Springer International Publishing Switzerland. 2016. ISBN 978-3-319-39558-6. 
  2. ^ Jean-Luc Chabert. A History of Algorithms: From the Pebble to the Microchip. Berlin, Heidelberg: Springer-Verlag. 1999. ISBN 978-3-642-18192-4. 
  3. ^ George M. Phillips. Mathematics Is Not a Spectator Sport. New York: Springer-Verlag. 2005. ISBN 978-0-387-28697-6. 
  4. ^ G. H. Hardy; E. M. Wright. An Introduction to the Theory of Numbers (Fourth Edition). Oxford: Clarendon Press. 1960. ISBN 978-0-19-853310-8. 
  5. ^ 5.0 5.1 Melissa E. O'Neill. The Genuine Sieve of Eratosthenes (PDF). Journal of Functional Programming. 2009, 19 (1): 95–106. doi:10.1017/S0956796808007004. 

拓展阅读[编辑]