Find all prime numbers within the natural number n (general algorithm, Escherichia sieve method and Euler sieve method)

    A prime number, also known as a prime number, refers to a number greater than 1 that cannot be divisible by other natural numbers except 1 and the integer itself. In other words, a natural number that has only two positive factors (1 and itself) is a prime number. Numbers greater than 1 but not prime are called composite numbers. 1 and 0 are neither prime nor composite. Composite numbers are obtained by multiplying several prime numbers together.

    Judgment of prime number:

    1. Divisible only by 1 and itself.

    2. A prime number is a prime number that cannot be divisible by all prime numbers less than its square root.

1. Conventional algorithm

    Use the definition directly to determine whether n is a prime number, then use 2~n-1 to divide n, if it is divisible, it is not a prime number, otherwise it is a prime number. code show as below:

    Time complexity of finding all prime numbers within n: O(n²)

def isprime(n):
    for j in range(2, n):     # 2~n-1,不包括n
        if (n % j == 0):      # 能被2~n-1(不包括n)整除,不是素数
            return False
    else:
        return True           # 循环正常结束是素数(没有被整除)

P = []
for i in range(2, 10**8+1):   # 求10⁸以内的素数
    if isprime(i):
        P.append(i)

print(P)

2. Conventional optimization algorithm

    The number of cycles in the above algorithm is 2~n-1, n-2 times in total. Because the factors appear in pairs, one is less than or equal to the arithmetic square root, and the other is greater than or equal to the arithmetic square root. So you only need to test whether there is a factor less than or equal to the arithmetic square root. If it exists, it is not a prime number, otherwise it is a prime number. code show as below:

    Find the time complexity of all prime numbers within n: O(n\sqrt{n}), that isO(n^{1.5})

def isprime(n):
    j = 2
    while j * j <= n:         # j为2~n**0.5
        if (n % j == 0):       # 能被2~n-1(不包括n)整除,不是素数
            return False
        j += 1
    else:
        return True            # 循环正常结束是素数(没有被整除)

P = []
for i in range(2, 10**8+1):   # 求10⁸以内的素数
    if isprime(i):
        P.append(i)

print(P)

3. Optimizing with the Essieve method

    What is an Essieve sieve? The Eratosthene sieve method, referred to as Eratosthene sieve or Eratosthenes sieve, is a simple algorithm for checking prime numbers proposed by the Greek mathematician Eratosthenes. To get all prime numbers within the natural number n, the multiples of all prime numbers not greater than the root sign n must be eliminated, and the rest are prime numbers. To get all prime numbers within the natural number n, the multiples of all prime numbers not greater than n must be removed, and the rest are prime numbers.

     In short: it is to remove all the numbers that are multiples of prime numbers, and the remaining numbers are prime numbers.

Figure 1 Schematic diagram of the Essieve sieve, finding prime numbers within 100

    If a is a composite number, then a can be expressed as a=pq, where p,q>1. It is easy to prove that one of p and q must not exceed \sqrt{a}(if both p and q exceed \sqrt{a}, then a<pq). More strictly, if a is a composite number, then there must be a prime number p|a, and p≤ \sqrt{a}.

    So you only need to use all the prime numbers (2, 3, 5, 7) not exceeding 10 to find out, and then delete all their multiples within 100 (multiples of 2, multiples of 3, multiples of 5, multiples of 7), All composite numbers within 100 are deleted, and the rest are prime numbers within 100. code show as below:

    Time complexity of finding all prime numbers within n: O(nlog(logn))

def Eratosthene_sieve(n):   # 埃氏筛法求2到n范围内所有素数
    es = []
    Td = [1] * (n + 1)      # 0~n,n+1个元素
    for i in range(2, n + 1):
        if Td[i]:
            es.append(i)
            for j in range(i ** 2, n + 1, i):
                Td[j] = 0
    return es

P = Eratosthene_sieve(10**8): # 求10⁸以内的素数
print(P)

    Faster Elsieve sieve method:

def Eratosthene_sieve(n):
    P = []
    f = []
    for i in range(n + 1):    # 可以用f=[1]*(n+1)初始化f, f有n+1个元素(0-n)
        if i > 2 and i % 2 == 0:    # 此处在初始化时同时筛除了2的倍数,一半被筛
            f.append(1)
        else:
            f.append(0)
    i = 3
    while i * i <= n:         # 用3~n**0.5进行筛
        if f[i] == 0:
            j = i * i
            while j <= n:
                f[j] = 1
                j += i + i
        i += 2

    P.append(2)               # 将素数放入列表P中
    for x in range(3, n + 1):
        if f[x] == 0:
            P.append(x)

    return P

P = Eratosthene_sieve(10**8): # 求10⁸以内的素数
print(P)

    A more extreme Essieve method:

    Make full use of Python's characteristic operations: list generation and slice operations.

def Eratosthene_sieve(n):   # 埃氏筛法求2到n范围内所有素数
    es = [i for i in range(2, n+1)]
    L=len(es)
    for i in range(L):
        p = es[i]
        if p != 0:
            es[i+p:L:p] = [0]*len(es[i+p:L:p])
    es = list(filter(lambda x: x != 0, es))
    return es

P = Eratosthene_sieve(10**8): # 求10⁸以内的素数
print(P)

4. Optimization with Euler sieve method

    The Elder sieve method will repeat the sieve, increasing the time complexity. For better optimization, the Euler sieve will be used.

    Euler sieve method (Euler sieve method): On the basis of the Esperanto sieve (also use multiples of prime numbers to sieve out non-prime numbers, composite numbers can only be sieved by its smallest prime factor, such as 20, only its The minimum prime factor 2 is used to screen out, and 4 or 5 cannot be used to screen out).

    Unlike the Esperanto sieve, the Euler sieve does not repeatedly sieve a number, thus reducing the time complexity.

    The core of the Euler sieve is if I % p[j]==0: break, the code is as follows:

    The time complexity of the Euler sieve method is O(n).

def euler_sieve(n):
    f = [1] * (n + 1)
    p = []
    for i in range(2, n + 1):
        if f[i]:
            p.append(i)
        for j in range(len(p)):
            if i* p[j] > n:
                break
            f[i * p[j]] = 0
            if i % p[j] == 0:
                break
    return p

P = euler_sieve(10**8):   # 求10⁸以内的素数
print(P)

    When testing the correctness of the above algorithms, you can set the value of n a little smaller, and change 10**8 in each example to 10**4, otherwise the execution time of print(P) will be very long. When testing the execution efficiency of each of the above algorithms, please delete print(P), or change print(P) to print(len(P)), and please add a time module to record the start time and end time. Find the time difference.

Guess you like

Origin blog.csdn.net/hz_zhangrl/article/details/131474920