【问题标题】:Sieve of Eratosthenes speed differences埃拉托色尼筛速度差异
【发布时间】:2014-01-20 18:51:43
【问题描述】:

为什么第一个比第二个快这么多?我知道将素数存储为 1 和 0 更简单,但速度的提高是荒谬的。最后,它仍然遍历了一个长达 200 万个项目的列表,这怎么可能在 1 秒内完成编译?

def prime_sieve(limit):
    primes = [1 for x in xrange(limit)]
    primes[0] = 0
    primes[1] = 0
    imax = int(math.sqrt(limit) + 1)

    i = 2
    while (i < imax):
        j = i + i
        while j < limit:
            primes[j] = 0
            j += i
        while True:
            i += 1
            if primes[i] == 1:
                break
    return primes

s = prime_sieve(2000000)
print(sum(i for i in xrange(len(s)) if s[i] == 1))
-----------------------------------------------------------
def sieve(max):
    primes = range(2, max+1)
    for i in primes:
        j = 2
        while i * j <= primes[-1]:
            if i * j in primes:
                primes.remove(i*j)
                j += 1
    return primes

count = 0
for x in sieve(2000000):
    count += x
print count

【问题讨论】:

  • 这个问题似乎是题外话,因为它属于codereview.stackexchange.com
  • 在两个最外面的循环中添加一个print i,并为一些小的输入运行这两个函数,比如100。看看在这两个函数中测试了哪些数字!
  • 代码中有一个错误(除了函数sieve内部明显错误的缩进):从底部算起的第6行应该与上面的if取消缩进相同的水平它。

标签: python python-2.7 primes sieve-of-eratosthenes


【解决方案1】:

因为当您删除内容时,您将无法再使用direct addressing。直接寻址是筛选 Eratosthenes 速度的关键(类似于integer sorting 相对于基于比较的排序的速度优势)。

在您的第一个代码中,primes[j] = 0 是一个 O(1) 操作。但在第二种情况下,primes.remove(i*j) 是一个 O(n) 操作(根据this)。

您还开始在2*i 而不是i^2 处枚举i 的倍数。与上述相比,问题要小得多。

要正确比较算法速度,请始终比较 empirical orders of growth。这里是the results

# First code:
# --i+i--                                 # --i*i--
#   N       n    time-space   ~ n^        #    N     n     time-space   ~ n^
#  10k     1229  0.02s-7.9M               #
#  2mln  148933  1.13s-7.9M               #  2mln  148933  1.12s-7.9M  
#  4mln  283146  2.30s-7.9M  n^1.11       #  4mln  283146  2.25s-7.9M  n^1.09
#  8mln  539777  4.58s-7.9M  n^1.07       #  8mln  539777  4.38s-7.9M  n^1.03
# 16mln 1031130  9.12s-7.9M  n^1.06       # 16mln 1031130  8.82s-7.9M  n^1.08

# Second code:
# --j=2--                                 # --j=i--
#   5k      669  0.35s-7.9M               #   5k      669  0.28s-7.9M
#  10k     1229  1.37s-7.9M  n^2.24       #  10k     1229  1.16s-7.9M  n^2.34
#  20k     2262  5.21s-7.9M  n^2.19       #  20k     2262  4.66s-7.9M  n^2.28
#  30k     3245 11.76s-7.9M  n^2.26       #  30k     3245 11.24s-7.9M  n^2.44

N 是上限,n - 低于它的素数数。指数当然是近似的,它们的增量没有被测量,但它们确实为我们提供了一个总体情况。二次(或更差)算法肯定与线性算法大不相同。

【讨论】:

    猜你喜欢
    • 2011-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多