检索Python集的次最小元素
这是一种相当快速的方法,可以生成小于等于检索Python集的次最小元素,python,algorithm,data-structures,Python,Algorithm,Data Structures,这是一种相当快速的方法,可以生成小于等于k极限的素数,如下所示: 从集合p=(2,3,4,…,k)和i=2开始 从i^2开始,从p中删除所有倍数的i 对p中下一个最小的i重复,直到i>=sqrt(k) 我当前的实现如下所示(对所有偶数进行了明显的预过滤优化): 编辑:以下是等效的列表代码: def sieve_list(k): s = [True] * k s[0] = s[1] = False for i in range(4, k, 2): s[i]
k
极限的素数,如下所示:
p=(2,3,4,…,k)
和i=2
开始i^2
开始,从p
中删除所有倍数的i
p
中下一个最小的i
重复,直到i>=sqrt(k)
列表
代码:
def sieve_list(k):
s = [True] * k
s[0] = s[1] = False
for i in range(4, k, 2):
s[i] = False
for i in range(3, int(sqrt(k)) + 2, 2):
if s[i]:
for j in range(i ** 2, k, i * 2):
s[j] = False
return [2] + [ i for i in range(3, k, 2) if s[i] ]
这是可行的,但并不完全正确。台词:
for i in range(3, int(sqrt(k)), 2):
if i in s:
[...]
通过测试每个奇数的集合成员资格,找到s
的下一个最小元素。理想情况下,实施应该是:
while i < sqrt(k):
[...]
i = next smallest element in s
而i
但是,由于set
是无序的,因此我不知道如何(或者即使可能)以更有效的方式获得下一个最小的元素。我已经考虑过使用带有True
/False
标志的list
作为素数,但是您仍然需要遍历list
以查找下一个True
元素。您也不能从列表中实际删除元素,因为这使得在步骤2中无法有效地删除复合数字
有没有办法更有效地找到下一个最小的元素?如果没有,是否有其他数据结构允许按值删除O(1)
以及找到下一个最小元素的有效方法 您可以使用列表而不是集合。对于未标记的,使用None初始化列表。您可以使用元素索引作为编号
初始化列表
从p=2开始
将列表中的p
的所有倍数标记为“M”表示已标记
在列表中找到下一个未标记的元素,并使其成为新的p
。如果没有,你就完了
如果需要查找下一个未标记的索引,只需查看索引p
之后的元素,这些元素等于零 集是无序的,因为它们在内部实现为哈希集。在这样的数据结构中,没有有效的方法来寻找最小元素min(s)
将是最具python风格的方式(但它是O(n))
您可以将collections.deque
与集合一起使用。使用deque
按排序顺序存储元素列表。每次需要获取最小值时,从deque
中弹出元素,直到找到集合中的元素。这在整个输入数组中分摊了O(1)成本(因为只需弹出n次)
我还应该指出,不可能有任何数据结构具有O(n)从列表创建(或O(1)插入)、O(1)按值移除和O(1)最小查找;这样的数据结构可以用来实现O(n)一般排序,这在信息论上是不可能的。哈希集非常接近,但必须牺牲有效的最小查找。我在问题中已经提到使用列表。列表的问题在于它是按位置而不是值索引的,因此在步骤2中无法有效地删除非素数。很抱歉,我没有仔细阅读。我认为您应该避免多次标记非素数。你认为从集合中删除非素数会使算法更快吗?我最初是使用list
(请参见编辑)实现这一点的,但遇到了同样的问题——你仍然必须迭代每个奇数才能找到下一个素数。使用list
或set
.p.s.我看不出有什么办法可以解决这个问题。如果您使用的是Python2.x,请使用xrange
避免每次都创建一个列表。如果您分析您的算法,它实际上非常有效。如果我在s中调用,则只执行O(n)。算法的其余部分至少是O(n),因为必须构造列表并从中删除O(n)个元素。因此,找到最小值的“低效”方法不会影响算法运行时间的顺序。O(sqrt(n))
实际上调用了它,所以现在我想起来,与过程的其余部分相比,它可能几乎没有成本。我也意识到我无法改善渐进复杂性,我只是在寻找一些小的%的改进。这是不可能的,当你把它放在排序方面时,它是如此明显!不过,我不确定一个deque
怎么能给我带来任何好处,而不仅仅是在奇数中穿行,如果我在s中做。hashset成员资格不是有效的O(1)吗?是的,是的。就你而言,我认为你已经达到了合理需要的效率。如果您随机删除元素,deque会有所帮助。谢谢。有趣的是,列表版本更快,即使您只返回集合而不进行排序(对于k
=30M,4秒对7.5秒)。我希望集合速度更快。set.discard
比list[I]=False
慢,这是代码中的热循环(因为set.discard
需要散列、bucket查找、可能的集合大小调整等,list[I]
只是一个列表索引操作)。类似地,如果我在集合中
比如果列表[i]
慢。
while i < sqrt(k):
[...]
i = next smallest element in s