Eratosthenes筛选优化

时间:2013-10-26 15:04:35

标签: python optimization

几周前我在python中编写了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秒。

关于我算法中的一些更优化的想法?谢谢!

4 个答案:

答案 0 :(得分:4)

i += 1 

在最后一个循环中很有趣。

考虑更换

for i in rangeLenA: 

for i in xrange(LenA) 

你避免生成一个你不需要的巨大列表。

编辑:

还要考虑这个:

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

而不是:

    while j < lenA:

修复错误

while A[i] <= raiz: 
按照fryday的建议。

答案 1 :(得分:2)

您的代码中存在错误。变化

while A[i] < raiz:

while A[i] <= raiz:

当N为方形时,您可以发现错误。

对于opimization,使用 xrange rangeLenA 而不是范围

答案 2 :(得分: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个用于邮件的时间(1000)和26毫秒。让我感到惊讶的是它太慢了。

函数式编程它更有趣,但在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标志列表。直观地说,看起来迭代更快,对吧?

我的结果是,对于erathostenes_imperative(100000)为831ms,而您的版本为1.45。

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

答案 3 :(得分:1)

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

但是,由于您不熟悉编程,因此最好是实现其他算法,或者进行其他编程练习来改进。