当前位置: 首页 > 知识库问答 >
问题:

为什么我筛厄拉多塞这么慢?

扶冠宇
2023-03-14

我正在解决欧拉项目的一些问题,必须生成200万质数来解决一个问题。我对埃拉托色尼筛的实现非常慢,但我不知道为什么。有人能解释一下这个实现的主要问题吗?我觉得它很漂亮,然后我发现它非常糟糕:(。我在网上找到了它的另一个实现,它比我的快得多。

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

编辑:感谢所有的答案!结论是过滤器是问题所在,因为它会遍历每个元素(而不仅仅是那些被标记为非素数的元素),而且每次都会创建一个新列表。用旧的循环和一轮过滤重写它,它的工作速度要快得多。新代码:

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

共有2个答案

池宸
2023-03-14

运行 c配置文件显示大部分时间都花在筛选器中。将筛选器替换为列表理解可将速度加快约 2 倍。

numbers = [n for n in numbers if n%prime != 0]

但这并没有真正解决主要问题,即每次迭代都要重新创建数字列表,这很慢。更快的实施http://groups.google.com/group/comp.lang.python/msg/f1f10ced88c68c2d只需将非素数替换为0或类似即可。

闾丘照
2023-03-14

厄拉多塞的筛子看起来像这样:

def sieve(n):
    primality_flags = [True]*(n+1)
    primality_flags[0] = primality_flags[1] = False
    primes = []
    for i, flag in enumerate(primality_flags):
        if flag:
            primes.append(i)
            for j in xrange(2*i, n+1, i):
                primality_flags[i] = False
    return primes

当外部循环到达时,它对每个数字处理一次,并且对每个除尽它的素数处理一次。大约1/2的数字能被2整除,大约1/3的数字能被3整除,以此类推;渐近地说,每个数将被处理的平均次数是1直到n的素数的倒数之和。这个和大约是< code>log(log(n)),所以假设算术是常数时间,则筛子具有渐近时间复杂度< code > O(n * log(log(n))。这真的很好。

你的函数不会这样做。您的过滤器遍历numbers中的每个元素,而不管它是否可以被 numbers元素。让素数序列为p[0]、p[1]、p[2]等,让 的大小序列为n[0]、n[1]、n[2]等,我们得到以下近似递推: 元素,直到第一个素数将其分开为止,处理素数p会删除大约1>

n[0] = upperBound - 1
n[1] = n[0] * (p[0]-1)/p[0]
n[2] = n[1] * (p[1]-1)/p[1]
...
n[k+1] = n[k] * (p[k]-1)/p[k]

你的算法需要的时间大致与n值的总和成正比,直到数字为空。我没有分析该系列的行为,但计算显示增长比O(n*log(log(n)))差得多。(编辑:我在编写这个答案时没有想到的分析说是O((n/log(n))^2)。)

 类似资料:
  • 我选择了“使用C进行编程原理和实践”,并且正在做一个涉及埃拉托色尼筛的早期问题,我有意想不到的输出,但我无法确定问题到底是什么。这是我的代码: 这个问题目前只要求我使用这种方法找到最大100的质数。我还尝试使用当前的“goto”方法在某些情况下跳出双循环,我还尝试在检查循环之后使用带有if语句的布尔标志,并简单地使用“继续”语句,但都没有任何效果。 (老实说,我想既然人们说goto是邪恶的,也许它

  • 我用Python2.7编写了一段代码,用于创建质数列表。代码是 这是否比埃拉托斯特尼筛更有效?我认为记忆效率应该更好,但我怀疑时间效率。如何计算时间和内存效率,以及如何对效率进行基准测试?

  • 我有一个问题,我有一个需要使用数组的赋值。我需要创建埃拉托斯特尼筛算法并打印出所有素数。我很困惑,因为据我所知,我的操作顺序是正确的。代码如下: 我首先将数组中的所有数字设置为true。然后第二个循环将从2开始“x”,然后在其中是一个嵌套循环,它将“x”乘以“n”的值,并且只要乘积(“y”)小于1000,“n”就会继续增加。一旦“y”达到最大值,“x”就会增加一个数字,重复该过程,直到所有非质数都

  • 我必须为'sieve of eratosthenes'算法编写一个java代码,以便在控制台上打印出给定最大值的素数,但我不被允许使用数组。我们的教授告诉我们,只有在循环的帮助下才能做到这一点。 所以我想了很多,在谷歌上搜索了很多关于这个话题的信息,但都找不到答案。我认为这根本不可能,因为你已经把那些数字已经被划掉的信息存储在某个地方了。 我的代码到现在为止: - 但是如果有一个解决方案,如果有人

  • 我正在为厄拉多塞的筛子用Python写一个素数程序。虽然看起来很管用,但是很慢。我该如何加快速度呢? 更新:由于答案的帮助,我用布尔值而不是数字重写了代码。低于100000的列表现在运行时间不到6秒。

  • 问题内容: 我应该开发一个简单的SFTP。 一切都进行得很好,直到我(在本例中)没有编写全部为止。可以请我解释一下,为什么系统挂在我身上吗? 服务器端: 客户端: 问题答案: 您的循环一直运行到流结束,但是对等方永远不会关闭套接字。该协议似乎要求打开套接字以供其他命令使用,因此您必须调整它的这一部分以包括一个长度字前缀,以便您知道要复制多少字节。 问题不是关于不写所有字节,而是关于阻塞in 。