【发布时间】:2015-08-12 20:37:14
【问题描述】:
我正在解决 Project Euler 的一些问题,并且必须生成 200 万个素数才能解决问题。我的 Eratosthenes 筛的实施结果非常缓慢,但我不太清楚为什么。有人可以解释一下这个实现的主要问题。我觉得它很漂亮,然后我发现它非常糟糕:(。我在网上找到了它的另一个实现,它比我的快得多。
def generatePrimes(upperBound):
numbers = range(2,upperBound+1)
primes = []
while numbers:
prime = numbers[0]
primes.append(prime)
numbers = filter((lambda x: x%prime),numbers)
return primes
编辑:感谢所有答案!对此的结论是过滤器是问题所在,因为它会遍历每个元素(而不仅仅是那些被标记为非素数的元素),并且因为它每次都会创建一个新列表。用旧的 for 循环和一轮过滤重写它,它的工作速度更快。新代码:
def generatePrimes(upperBound):
numbers = range(2,upperBound+1)
for i in xrange(len(numbers)):
if(numbers[i] != 0):
for j in xrange(i+numbers[i],len(numbers),numbers[i]):
numbers[j] = 0
primes = filter(lambda x: x,numbers)
return primes
【问题讨论】:
-
这是python2还是python3?
-
一方面,它不是埃拉托色尼的筛子。这是trial division。
-
我认为这在技术上是一个筛子,但您在每次迭代中使用 filter 函数执行大量分配。大多数筛子都经过优化,只执行一次大型数组分配,而您的筛子则从 len(upperBound) 开始执行 O(n) 大小的分配。
-
@dustyrockpyle:不,这与埃拉托色尼筛法有很大不同。当外部循环到达每个数字时,SoE 处理每个数字一次,并在其素数分解中的每个素数处理一次;这个函数为每个素数处理一个数字,直到它的第一个素数因子。事实证明,平均而言,每个数字查看的次数要多得多。
-
当你测试的素数大于 sqrt(upperBound) 时,有助于打破循环的一件事,因为剩下的任何东西都保证是素数。
标签: python performance algorithm time-complexity primes