Python Eratosthenes筛算法优化

Python Eratosthenes筛算法优化,python,optimization,primes,sieve-of-eratosthenes,Python,Optimization,Primes,Sieve Of Eratosthenes,我正试图实施埃拉托什尼的筛选。输出似乎是正确的(减去需要添加的“2”),但如果函数的输入大于100k左右,则似乎需要花费过多的时间。我可以通过哪些方式优化此功能 def sieveErato(n): numberList = range(3,n,2) for item in range(int(math.sqrt(len(numberList)))): divisor = numberList[item] for thing

我正试图实施埃拉托什尼的筛选。输出似乎是正确的(减去需要添加的“2”),但如果函数的输入大于100k左右,则似乎需要花费过多的时间。我可以通过哪些方式优化此功能

def sieveErato(n):
     numberList = range(3,n,2)

     for item in range(int(math.sqrt(len(numberList)))):
            divisor = numberList[item]
            for thing in numberList:
                    if(thing % divisor == 0) and thing != divisor:
                            numberList.remove(thing)
    return numberList

你可以像埃拉托什内斯那样尝试。取一个包含所有需要检查升序的数字的数组,转到数字2并标记它。现在,每秒钟划一次数字,直到数组结束。然后转到3并标记它。在那之后,每三个数字就刮一次。然后转到4-它已经被划伤了,所以跳过它。对尚未划伤的每n+1重复此步骤

最后,标记的数字是素数。该算法速度更快,但有时需要大量内存。您可以通过删除所有偶数(因为它们不是素数)并手动将2添加到列表中来稍微优化它。这会稍微扭曲逻辑,但会占用一半的内存


下面是我所说内容的一个示例:

警告:在迭代器上进行迭代时从迭代器中删除元素可能会非常密集

你可以做这个

    if(thing % divisor == 0) and thing != divisor:
测试打火机时,将其拆分到循环中,循环在到达“除数”索引时中断,然后测试:

for thing in numberList_fromDivisorOn:
    if(thing % divisor == 0):
        numberList.remove(thing)
我遵循了这个链接:@MAK的建议,我发现我在您的代码中发现了一个想法,可以改进公认的答案:

def primes_sieve2(limit):
    a = [True] * limit               # Initialize the primality list
    a[0] = a[1] = False
    sqrt = int(math.sqrt(limit))+1
    for i in xrange(sqrt):
        isprime = a[i]
        if isprime:
            yield i
            for n in xrange(i*i, limit, i):     # Mark factors non-prime
                a[n] = False
    for (i, isprime) in enumerate(a[sqrt:]):
        if isprime:
            yield i+sqrt

如果给定无限的内存和时间,下面的代码将打印所有素数。而且它不使用试算法也能做到。它基于本文中的haskell代码:

从heapq导入heappush、heappop、HEAPPREPLACE
def sieve():
w=[2,4,2,4,6,2,6,4,2,4,6,6,2,6,4,2,6,6,8,4,4,2,4,4,4,4,8,6,4,6,2,6,6,4,2,4,4,4,6,6,6,4,4,6,2,6,4,4,2,10]
对于[2,3,5,7]中的p:print p
n、 o=11,0
t=[]
l=len(w)
p=n
heappush(t,(p*p,n,o,p))
打印p
尽管如此:
n、 o=n+w[o],(o+1)%l
p=n

如果不是t[0][0]你的算法就不是埃拉托斯坦的筛子。您可以执行试除法(模数运算符),而不是像两千多年前埃拉托斯提涅所做的那样,删除倍数。是对真实筛选算法的解释,下面是我简单、直接的实现,它返回不超过n的素数列表:

def筛(n):
m=(n-1)//2
b=[True]*m
i、 p,ps=0,3[2]
而p*p
我们只对奇数进行筛选,在n的平方根处停止。在被筛选的3,5,7,9等整数之间的j映射上的奇数计算。。。索引0,1,2,3。。。在b位数组中


您可以在中看到此函数的作用,它在不到一秒钟的时间内计算出一百万个素数。

此代码需要2秒钟才能生成小于10M的素数 (这不是我的,我在谷歌上找到的)

deferat_筛(绑定):
如果绑定小于2:
返回[]
max_ndx=(界-1)//2
筛子=[True]*(最大值+1)
#循环到平方根
对于范围内的ndx(int(绑定**0.5)//2):
#检查素数
如果筛[ndx]:
#取消标记素数的所有奇数倍数
num=ndx*2+3
筛子[ndx+num:max\u ndx:num]=[False]*((max\u ndx-ndx-num-1)//num+1)
#翻译成数字
如果筛选[ndx]],则返回范围内ndx的[2]+[ndx*2+3(最大值)]

我们可以从绘制分辨率时间作为n的函数开始,这可以给我们一些想法…谢谢Jason,我几天前读过这篇文章,很难理解给出的Eratosthenes函数。我想我明白我现在遗漏了什么。如果你遵循这个过程,你会不止一次地核对每个数字。可能只需要检查一次。请看我的答案。这将返回[2,3,5,7,1,3,7,9,13,19,21,27,31,33,37,43,49,51,57,61,63,69,73,79,87]的limit=100。这不仅是一个奇怪的重复,而且这些术语中的许多都不是素数。代码不仅没有打印11,而且似乎打印了许多11的素数倍数[121、143、187等等]。哎呀,我没看到,但解决方法很简单。如果你只打印出100以下的素数呢?你用过你的堆吗?它的起点是121。直到您签出121,或者签出以下100以下的所有素数的条目(当您达到100时,这些素数填充了您的堆),它才是必需的,但是还不需要。这是本文代码的一个主要缺陷,您在这里忠实地重新创建了该缺陷。只有在看到候选项时,才应将其添加到堆中,使其等于该素数的平方。因此,这段代码的内存需求是O(n)来打印n个素数,而不是O(sqrt(n/log(n))(contd.),而且由于它必须处理比实际需要大得多的堆,因此速度也会变慢。要产生1000000个素数,您只需要检查不超过550个素数;但是您的代码将在堆中存储99999个条目。梅丽莎·奥尼尔在她的ZIP文件中解决了这个问题。简单的实现应该是这样的。
from heapq import heappush, heappop, heapreplace
def sieve():
    w = [2,4,2,4,6,2,6,4,2,4,6,6,2,6,4,2,6,4,6,8,4,2,4,2,4,8,6,4,6,2,4,6,2,6,6,4,2,4,6,2,6,4,2,4,2,10,2,10]
    for p in [2,3,5,7]: print p
    n,o = 11,0
    t = []
    l = len(w)
    p = n
    heappush(t, (p*p, n,o,p))
    print p
    while True:
        n,o = n+w[o],(o+1)%l
        p = n
        if not t[0][0] <= p:
            heappush(t, (p*p, n,o,p))
            print p
            continue
        while t[0][0] <= p:
            _, b,c,d = t[0]
            b,c = b+w[c],(c+1)%l
            heapreplace(t, (b*d, b,c,d))
sieve()
def sieve(n):
    m = (n-1) // 2
    b = [True]*m
    i,p,ps = 0,3,[2]
    while p*p < n:
        if b[i]:
            ps.append(p)
            j = 2*i*i + 6*i + 3
            while j < m:
                b[j] = False
                j = j + 2*i + 3
        i+=1; p+=2
    while i < m:
        if b[i]:
            ps.append(p)
        i+=1; p+=2
    return ps
def erat_sieve(bound):
    if bound < 2:
        return []
    max_ndx = (bound - 1) // 2
    sieve = [True] * (max_ndx + 1)
    #loop up to square root
    for ndx in range(int(bound ** 0.5) // 2):
        # check for prime
        if sieve[ndx]:
            # unmark all odd multiples of the prime
            num = ndx * 2 + 3
            sieve[ndx+num:max_ndx:num] = [False] * ((max_ndx-ndx-num-1)//num + 1)
    # translate into numbers
    return [2] + [ndx * 2 + 3 for ndx in range(max_ndx) if sieve[ndx]]