检索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