2013-10-26 23 views
4

我用Python编写的erathostenes算法在几个星期前,它看上去像下面这样:Erathostenes筛优化

def erathostenes(n): 

    A = range(2,n+1) 
    B = [] 
    i = 0 

    while A[i] < math.sqrt(n): 
     B.append(A[i]) 
     j = i 
     aux = A[i] 
     while j < len(A): 
      if A[j]%aux == 0: 
       A[j] = 0 
      j += aux 
     i += 1 
     while A[i] == 0: 
      i += 1 
    for i in range(len(A)): 
     if A[i] != 0: 
      B.append(A[i]) 
     i += 1 
    return B 

想一点(我在编程小白)之后,我只是做了一些在我的算法的修改的右现在看起来像:

def erathostenes(n): 

    A = range(2,n + 1) 
    B = [] 
    i = 0 

    raiz = math.sqrt(n) 
    lenA = len(A)  
    rangeLenA = range(lenA) 

    while A[i] < raiz: 
     B.append(A[i]) 
     j = i 
     aux = A[i] 

     while j < lenA: 
      A[j] = 0 
      j += aux 
     i += 1 
     while A[i] == 0: 
      i += 1 
    for i in rangeLenA: 
     if A[i] != 0: 
      B.append(A[i]) 
     i += 1 
    return B 

如果我在n = 10.000.000在所述第一代码的执行时间执行的算法是大约7秒,并与所述第二代码是约4秒。

有关我的算法中更多优化的任何想法?谢谢!

+3

这是非常好的前期代码审查。 –

+1

还有其他算法,例如http://en.wikipedia.org/wiki/Sieve_of_Atkin – NPE

回答

4
i += 1 

在最后一个循环很有趣。

考虑与

for i in xrange(LenA) 

你避免产生你并不需要一个巨大的名单更换

for i in rangeLenA: 

编辑:

也可以这样考虑:而不是

for j in xrange(i,lenA,aux): 

while j < lenA: 

并修复错误

while A[i] <= raiz: 

通过fryday的建议。

+0

让我连接我自己的代码http://stackoverflow.com/questions/9043791/python-eratosthenes-sieve-algorithm-optimization/9043972#9043972 :-)几乎两时间更快在我的笔记本电脑像这样使用它:A = [我为我primes_sieve2(10000000)] – jimifiki

2

代码中有错误。在

while A[i] <= raiz: 

你可以发现错误时,N为方形更改

while A[i] < raiz: 

对于opimization使用x范围为rangeLenA代替范围

+0

我不知道xrage存在,谢谢你的信息。 xrange是一个更新版本的范围,我将它搁置? – Antoni

+1

**范围(n)**让您列出表格0至n-1例如范围(5)=(0,1,2,3,4) ** xrange(n)**获得xrange对象,该列表产生的值与列表中的值相同(n) 您可以在此处更详细地阅读它:http://docs.python.org/2/library/functions.html#xrange – fryday

1

尝试阿特金筛。它是相似的,但它是对Eratosthenes Sieve的修改,它过滤掉2,3,5的所有倍数,以及其他一些优化。您可能还想尝试找到一个工具,告诉您每个操作的运行时间,并用更长的运行时间修改操作。

但是,由于您是编程新手,您最好接受其他算法的实现或者进行其他编程练习以提高效果。

+0

必须指出的是,可以将轮子因子分解应用到Atkin筛中,就像它嵌入到Atkin筛中一样,事实上,SoE可以使用更高级别的车轮事实化,而SoA算法具有2/3/5车轮。具有最大车轮事件化的SoE程序被写入与基本SoA相同的复杂程度将比SoA达到10亿以上的范围,那么对于“一个巨大的存储器阵列”类型的实现将逐渐变慢,但是这对于巨大的存储器阵列尺寸来说可能不实际。 – GordonBGood

2

试图做一个非循环版本只是为了好玩。它出来是这样的:

def erathostenes(n): 

    def helper_function(num_lst, acc): 

     if not num_lst: 
      return acc 
     if len(num_lst) == 1: 
      acc.append(num_lst[0]) 
      return acc 
     num = num_lst.pop(0) 
     multiples = ([x for x in range(num + 1, num_lst[-1] + 1) 
         if x % num == 0]) 

     remains = ([x for x in num_lst if x not in multiples]) 
     acc.append(num) 
     return helper_function(remains, acc) 
    return helper_function(range(2, n + 1), []) 

,当我跑的时间,得到了826我们后erathostenes(1000),和我的版本26ms(!!)。让我感到惊讶,它太慢了。使用函数式编程更有趣,但看起来并不适合这个问题,在Python中(我的猜测是它会在更多的函数式语言中更快)。

所以我尝试了一个命令式的版本。它看起来像这样:

def erathostenes_imperative(n): 
    limit = int(math.sqrt(n)) 
    def helper_function(flags, size): 
     for i in range(2,limit): 
      if flags[i] == True: 
       j = 2*i 
       while j < size: 
        if j % i == 0: 
         flags[j] = False 
        j = j + i 
     return [x for x in range(2, n + 1) if flags[x]] 
    return helper_function([True]*(n + 1), n) 

我所做的是将整数列表更改为True/False标志列表。直观地说,看起来迭代速度更快,对吗?

我的结果其中831ms为erathostenes_imperative(100000),而你的版本为1.45。

令人遗憾的是,它的写作速度更快。代码看起来很杂乱,所有的fors,whiles,我和j的

+1

我不确定您的命令版本是否完全正确。如果您执行n = 10.000.000,那么素数应该是664579,而您的版本会给出664580(多一个)的结果。让我们看看我能否解决这个问题。谢谢! – Antoni

+0

大声笑。只是编辑,编辑回来不要破坏。 找到错误后,随时编辑我的文章! –