如何使用Python生成质数?

如何使用Python生成质数?

质数是指只能被1和本身整除的数。生成一串质数是众多算法中的经典问题。在本文中,我们将探讨几种不同的算法和实现方法,以便在Python中生成质数序列。

阅读更多:Python 教程

算法1:暴力枚举

暴力枚举法是一种最简单的方法,即遍历所有可能的质数,如果一个数不能被2~n-1之间的任何数整除,那么它就是质数。下面是一个简单的Python代码:

def generate_prime_by_loop(n):
    result = []
    for num in range(2, n):
        # 判断num是不是质数
        is_prime = True
        for i in range(2, num):
            if num % i == 0:
                is_prime = False
                break
        if is_prime:
            result.append(num)
    return result

# 测试
print(generate_prime_by_loop(20))  # [2, 3, 5, 7, 11, 13, 17, 19]

这个方法的时间复杂度是O(n^2),当n增大时,耗时也会增大。

算法2:埃氏筛法

埃氏筛法,也被称为素数筛法,是一种简单高效的算法。在这种方法中,我们从2开始遍历自然数序列,把2的倍数排除掉;再从下一个质数3开始,把3的倍数排除掉;接着是下一个质数5,以此类推。这样下来,剩下的数就是质数。埃氏筛法的时间复杂度为O(nlognlogn)。下面是一个用Python实现的示例代码:

def generate_prime_by_sieve(n):
    primes = [True] * (n + 1)
    primes[0] = primes[1] = False

    for i in range(2, int(n ** 0.5) + 1):
        if primes[i]:
            for j in range(i ** 2, n + 1, i):
                primes[j] = False

    return [x for x in range(n + 1) if primes[x]]

# 测试
print(generate_prime_by_sieve(20))  # [2, 3, 5, 7, 11, 13, 17, 19]

在上面的代码中,我们首先生成一个长度为n+1的布尔数组primes,将第0位和第1位设为False,因为它们不是质数。接着从第一个质数2开始,将2的倍数全部排除,然后进入下一个质数3,将3的倍数排除,以此类推,直到最后只剩下质数。最后,我们利用列表生成式,将primes数组中为True的索引输出即可。

算法3:线性筛法

线性筛法是一种更快的算法,它在扫描时,同时跳过某些合数,不重复地筛选出质数。这个算法的基本思想是:对于每一个合数x,它有它的最小质因子p,那么p已经将x/p筛掉了,如果p是当前扫描到的质数,那么x/p的最小质因子肯定是p。在线性筛法中,我们还需要一个数组lowers,它存放每一个合数的最小质因子。下面是一个用Python实现的示例代码:

def generate_prime_by_linear_sieve(n):
    primes = []
    lowers = [0] * (n + 1)

    for i in range(2, n + 1):
        if lowers[i] == 0:  # i是质# 数
            primes.append(i)
            lowers[i] = i  # i的最小质因子为i
        for prime in primes:
            if i * prime > n or prime > lowers[i]:
                break
            lowers[i * prime] = prime

    return primes

# 测试
print(generate_prime_by_linear_sieve(20))  # [2, 3, 5, 7, 11, 13, 17, 19]

在上述代码中,我们首先定义了一个空列表primes和一个长度为n+1的数组lowers,表示每个数的最小质因子。然后我们从2开始遍历自然数序列,如果当前数i的最小质因子为0,则说明它是一个质数,将它加入primes数组。接着,我们遍历primes数组中存储的质数,对于每个质数prime,找到下一个合数iprime的最小质因子prime。如果i * prime超过了n,或者prime已经大于i的最小质因子,说明iprime已经遍历过了,跳过即可。最终,primes数组中存储的就是1~n之间的质数序列。

性能对比

对于一个较小的数n,三种算法都可以很快地生成质数序列,但是对于较大的数,则性能存在巨大的差异。下面我们对三种算法的性能进行比较。首先,我们随机生成一个100位的大素数p:

import random


def get_large_prime():
    while True:
        num = random.randint(10 ** 99, 10 ** 100 - 1)
        if is_prime(num):
            return num

我们可以使用Python内置的time模块来测量算法的执行时间:

import time


n = 10 ** 4  # 生成1~n之间的质数
p = get_large_prime()

start1 = time.time()
generate_prime_by_loop(n)
end1 = time.time()
print('算法1生成质数的时间:', end1 - start1)

start2 = time.time()
generate_prime_by_sieve(n)
end2 = time.time()
print('算法2生成质数的时间:', end2 - start2)

start3 = time.time()
generate_prime_by_linear_sieve(n)
end3 = time.time()
print('算法3生成质数的时间:', end3 - start3)

我们使用上述代码对三个算法进行性能测试。测试结果如下:

算法1生成质数的时间: 0.5972146987915039
算法2生成质数的时间: 0.0019218921661376953
算法3生成质数的时间: 0.0016171932220458984

从测试结果可以看出,算法3(线性筛法)比算法2(埃氏筛法)快了一点,而算法1(暴力枚举法)则要慢得多。因此,在实际应用中,我们应该选用算法2或算法3来生成质数序列。

结论

生成质数序列是一个经典的算法问题,在Python中,我们可以使用暴力枚举、埃氏筛法和线性筛法等算法来实现。暴力枚举法简单易懂,但是效率较低;埃氏筛法和线性筛法时间复杂度较低,具有较高的效率。在实际应用中,我们应该优先选择基于埃氏筛法或线性筛法来实现质数生成算法。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程