算法学习|埃拉托斯特尼筛法
埃拉托斯特尼筛法(埃氏筛)
筛选出所有小于等于n的质数
步骤
- 初始化布尔数组:创建一个长度为
n+1
的数组is_prime
,初始时除0
和1
外,其他元素设为True
。 - **标记非质数:从
2
开始遍历到√n
,若当前数i
是质数,则将其所有倍数标记为非质数(从i²
开始)。 - 收集结果:遍历数组,收集所有标记为
True
的索引。
实现
def sieve_of_eratosthenes(n):
if n < 2:
return []
# 初始化布尔数组,默认所有数为质数
is_prime = [True] * (n + 1)
is_prime[0], is_prime[1] = False, False # 0和1不是质数
# 遍历到sqrt(n)
for i in range(2, int(n ** 0.5) + 1):
if is_prime[i]:
# 从i²开始标记,步长为i
for j in range(i * i, n + 1, i):
is_prime[j] = False
# 收集所有质数
primes = [i for i, prime in enumerate(is_prime) if prime]
return primes
# 示例
n = 30
primes = sieve_of_eratosthenes(n)
print(primes) # 输出 [2, 3, 5, 7, 11, 13, 17, 19, 23, 29](若n=30)
关键点解析
-
布尔数组初始化:
is_prime = [True] * (n + 1) is_prime[0], is_prime[1] = False, False
- 数组索引表示数值,
is_prime[i]
为True
表示i
是质数。
- 数组索引表示数值,
-
遍历范围优化:
for i in range(2, int(n ** 0.5) + 1):
- 只需遍历到
√n
,因为若n
有大于√n
的因数,其对应的小因数已被处理。
- 只需遍历到
-
标记倍数:
for j in range(i * i, n + 1, i): is_prime[j] = False
- 从
i²
开始标记,因为小于i²
的倍数(如i*2, i*3, ...
)已被更小的质数处理过。
- 从
复杂度分析
- 时间复杂度:O(n log log n),接近线性时间。
- 空间复杂度:O(n),存储布尔数组。
应用场景
- 快速生成质数表
- 解决数学问题中的质数相关问题
优化扩展
预筛小质数:预先处理小的质数(如2,3,5),减少标记次数。