【问题标题】:Sieve of Eratosthenes set-implementation confusion埃拉托色尼筛法设置实施混乱
【发布时间】:2015-10-20 01:14:02
【问题描述】:

我想先声明一下,我是一个 python 新手,我很感激任何能清楚完整地向我解释的人。

我正在查看以下链接中的代码:

http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Python

我刚刚开始了解迭代器、生成器和 yield 命令,但我不明白 set 实现的代码是如何工作的。

def eratosthenes2(n):
    multiples = set()
    for i in range(2, n+1):
        if i not in multiples:
            yield i
            multiples.update(range(i*i, n+1, i))

我很难理解这个函数的最后一行是做什么的。

另外,有人可以向我解释一下为什么这个实现是 O(log(n)) 时间吗?

【问题讨论】:

  • 谢谢格雷戈尔。感谢您抽出宝贵时间告诉我这一点,下次遇到问题时,我一定会牢记这一点

标签: python sieve-of-eratosthenes


【解决方案1】:

表达式range(i, j, k) 生成从ij 的整数列表(j 不包含在内,因此包含范围为j-1),间隔为k(其中默认为 1)。所以range(2, 10, 2) 生成列表[2, 4, 6, 8]

最后一行所做的是将ii2n 的所有倍数插入到集合multiples。我们从i2 开始,因为i 是一个素数(因为它没有在筛子中找到),而不在multiples 中的i 的下一个最小倍数是@987654337 @×i。证明:如果 i 的下一个最小倍数是等于 c × i 的值,对于某些 c 其中 1 i,那么我们已经在筛子中将其过滤掉了。我们在n+1 结束范围,因为这是筛子结束的地方(1 弥补了结束边界不包含在内的事实)。当然,我们的间隔设置为 i 以产生其倍数。

关于 O(log(n)) 的部分是指在公共集合实现中测试集合成员的时间复杂度,而不是完整的算法。整个算法的复杂度不能小于 O(n),因为外部循环运行n-1 次(从 2 到 n)。实际上,集合成员测试需要 O(1) 时间,因为 Python 集合是哈希表。或者,您可以使用 n bools 中的 list,这会以空间为代价获得更好的性能。

【讨论】:

  • 非常感谢!感谢您抽出宝贵时间帮助我理解
【解决方案2】:

最后一行:

multiples.update(range(i*i, n+1, i))

将从i 的平方到n 的所有i 的倍数添加到集合multiplesi 平方以下的任何倍数都将在较早的 i 的集合中。

Rosetta 没有说算法是 O(log(n)),当然不是,只是集合查找是 O(log(n)) 与列表 O(n)。原因是集合使用散列作为查找的手段,实际上平均 O(1) vs. O(n)

【讨论】:

  • Python set 查找是O(1),而不是O(log n);它基于散列,而不是二叉树或任何东西。在实践中,由于碰撞链接,它通常不仅仅是一次检查,但它并没有以有意义的方式与set 的大小相关联。
  • 我以为我在最后一句话中提到了这个,我错过了什么吗?
  • 该段的第一句暗示预期时间为O(log n)。错误在罗塞塔这边。很抱歉造成混乱。
  • 同意,Rosetta 夸大了集合查找的成本(平均),更好的来源是:wiki.python.org/moin/TimeComplexity
猜你喜欢
  • 1970-01-01
  • 2023-03-20
  • 1970-01-01
  • 1970-01-01
  • 2010-12-08
  • 2011-12-16
  • 1970-01-01
相关资源
最近更新 更多