首先要注意的是,你寫的不是篩埃拉托色尼。看看有多少迴路埃拉托色尼的太傻太天真篩執行:
def sieve1(n):
loops = 0
numbers = set(range(2, n))
for i in range(2, int(n ** 0.5) + 1):
for j in range(i * 2, n, i):
numbers.discard(j)
loops += 1
return sorted(numbers), loops
測試:
>>> sieve1(100)
([2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97],
178)
178環路100號(不包括排序)。對於100個號碼(不包括在端部過濾器)
>>> sieve2(100)
([2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97],
102)
102循環:這可以通過一些小的改動加以改進:
def sieve2(n):
loops = 0
numbers = range(0, n)
for prime in numbers:
if prime < 2:
continue
elif prime > n ** 0.5:
break
for i in range(prime ** 2, n, prime):
numbers[i] = 0
loops += 1
return [x for x in numbers if x > 1], loops
測試。現在看看你的:
def sieve3(n):
loops = 0
numbers = range(2, n)
for i in numbers:
for j in numbers:
if j != i and j % i == 0:
numbers.remove(j)
loops += 1
return numbers, loops
測試:
>>> sieve3(100)
([2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97],
663)
更糟糕:
>>> [sieve1(x)[1] for x in [100, 1000, 10000]]
[178, 2978, 41723]
>>> [sieve2(x)[1] for x in [100, 1000, 10000]]
[102, 1409, 16979]
>>> [sieve3(x)[1] for x in [100, 1000, 10000]]
[663, 28986, 1523699]
在n = 10000
,您的實現做幾乎100倍之多的工作!
我的建議是在做出「緊湊」之前創建一個合理的實現。代碼高爾夫可以很有趣,但是無論長度如何,它都不具有挑戰性,或者不像編寫高效的代碼那樣具有挑戰性。
也就是說,考慮這個單線程(如果您不計算導入,可以使用lambda x, y: x - y
代替operator.sub
)。這實現了第一個小改進的算法:
>>> from operator import sub
>>> reduce(sub, (set(range(x ** 2, 100, x)) for x in range(2, int(100 ** 0.5) + 1)), set(range(2, 100)))
set([2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97])
「類型錯誤:‘類型’對象不可迭代「 - 任何想法爲什麼? – Parseltongue
@Parseltongue,我敢打賭,這是因爲你使用'list'(即內置列表構造函數)作爲變量名。 – senderle
你是怎麼神奇地發現的?輝煌 – Parseltongue