【发布时间】:2012-09-16 15:59:56
【问题描述】:
Sieve of Eratosthenes 是一种相当快的生成素数的方法,其上限为k,如下所示:
- 从
p = (2, 3, 4, ..., k)和i = 2集合开始。 - 从
i^2开始,从p中删除所有i的倍数。 - 在
p中重复下一个最小的i,直到i >= sqrt(k)。
我当前的实现是这样的(预过滤所有偶数的明显优化):
# Compute all prime numbers less than k using the Sieve of Eratosthenes
def sieve(k):
s = set(range(3, k, 2))
s.add(2)
for i in range(3, int(sqrt(k)), 2):
if i in s:
for j in range(i ** 2, k, i * 2):
s.discard(j)
return sorted(s)
编辑:这是基于 list 的等效代码:
def sieve_list(k):
s = [True] * k
s[0] = s[1] = False
for i in range(4, k, 2):
s[i] = False
for i in range(3, int(sqrt(k)) + 2, 2):
if s[i]:
for j in range(i ** 2, k, i * 2):
s[j] = False
return [2] + [ i for i in range(3, k, 2) if s[i] ]
这可行,但并不完全正确。行:
for i in range(3, int(sqrt(k)), 2):
if i in s:
[...]
通过测试每个奇数的集合成员关系,找到s 的下一个最小元素。理想情况下,实现实际上应该是:
while i < sqrt(k):
[...]
i = next smallest element in s
但是,由于set 是无序的,我不知道如何(或者即使可能)以更有效的方式获取下一个最小元素。我考虑过使用list 和True/False 标志作为素数,但您仍然需要通过list 寻找下一个True 元素。您也不能直接从 list 中删除元素,因为这使得在第 2 步中有效地删除复合数字变得不可能。
有没有办法更有效地找到下一个最小的元素?如果没有,是否有其他一些数据结构允许 O(1) 按值删除以及找到下一个最小元素的有效方法?
【问题讨论】:
-
附注如果您使用的是 Python 2.x,请使用
xrange以避免每次都创建一个列表。 -
如果你分析你的算法,它实际上非常有效。你只做 O(n)
if i in s电话。算法的其余部分至少为 O(n),因为您必须构建列表并从中删除 O(n) 元素。因此,找到最小值的“低效”方式不会影响算法运行时间的顺序。 -
O(sqrt(n))实际上是调用,所以现在我想它可能与其他过程相比几乎没有成本。我也意识到我无法提高渐近复杂度,我只是在寻找一些小的 % 改进。
标签: python algorithm data-structures