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