【问题标题】:Time complexity of an algorithm to find prime numbers求素数的算法的时间复杂度
【发布时间】:2014-08-06 01:40:21
【问题描述】:

我对素数很好奇,并想知道找到相对较小的素数的最有效方法,范围可达 1000 万。我读到 Erastosthenes (SOE) 的筛子是找到较小素数的最有效方法。我使用 python 实现了 SOE,但有几个问题:

  1. 我的算法的最坏情况运行时间似乎是 O(n^2)。我还在学习,所以我知道这个算法可以变得更高效。

  2. 找出素数的最有效的数学方法和最有效的编程方法有区别吗?在数学上,SOE 是最快的之一,但在编程方面,SOE 有那么快吗?

    def FindPrime(n):
        primes = [2, 3]
        for num in range(4, n):
            notprime = False
            for p in primes:
                if num % p == 0:
                    notprime = True
            if notprime == False:
                primes.append(num)
    
        print primes
    
    print FindPrime(100)
    

【问题讨论】:

  • 但是普通的 Python 在任何大的和数学上都没有效率。
  • @Jason S - 使用 Python 与算法的渐近 复杂性/效率完全无关,除非它提供了一组特定的方便的现成构建块。假设您使用相同的算法(使用相同的算法构建块),Python 可能会比 C 或 C++ 慢,但仅是常数因素。关于渐近分析(大 O 等)的一个关键点是常数因素是不相关的。
  • 该问题询问了数学和编程效率之间的差异。如果它真的只是关于算法,那是一个骗局。
  • 人们已经回答了您的问题,但我只想指出,由于素数定理,您的算法的运行时间为 n^2/log n(内循环为 n 阶/log n).

标签: python algorithm primes sieve-of-eratosthenes


【解决方案1】:

首先,您应该知道您的算法不是sieve of Eratosthenes。您正在使用试用部门。

可以对您的实施进行许多改进。

  1. 使用xrange(),即O(1),而不是range(),即O(n)

  2. 在搜索中跳过偶数:xrange(4, n, 2) 每次步骤 2。

  3. p > sqrt(n) 时,不要测试素数p 是否整除n。这是不可能的。

正如您预测的那样,这些更改不会影响复杂性的顺序,但您会看到性能的显着提升。

至于更快的算法,首先实现一个真正的埃拉托色尼筛,然后尝试更快的sieve of Atkin

【讨论】:

  • 很高兴知道。你能在python中实现erastosthenes的筛子吗?很想看看它是如何用这种语言编码的。
  • 当您使用优化的代码时,阿特金斯筛子仅比 Erathones 版本快得多。请参阅cr.yp.to/primegen/primegen-0.97.tar.gz 获取来自改进筛的原作者的源代码的当前版本。
  • 阅读我引用的源代码,您将看到优化的代码。它在算法上是不透明的,很难做到正确。但它确实跑得很快。建议编写阿特金版本对于新手问题来说是浪费时间;尤其是在蟒蛇。 Python 在很多方面都很棒,通用速度不是其中之一,即使是 PyPy、Psyco 和 Pyrex 等。
  • 派一个新手来写 C++ 是在浪费他的时间。这就是学习。
【解决方案2】:
  1. uʍopǝpısdn 是对的,您的代码不是 SOE

  2. 你可以找到我的 SOE 实现here

    • 这使得主要发现比您的解决方案更有效
  3. 国有企业矿山实施的复杂性

    • 时间:T(0.5·n·DIGAMMA(CEIL(SQRT(n))+0.3511·n) 如果使用 sqrt(N),如代码内注释中建议的那样
    • 时间(n=1M):T(3.80*n)
    • 时间(n=10M):T(4.38*n)
    • 时间(n = 100M):T(4.95*n)
    • 时间(n=1000M):T(5.53*n)
    • 所以大约运行时间是:T((0.3516+0.5756*log10(n))*n)
    • 所以复杂度是O(n.log(n))
  4. 速度(运行时)和复杂度 O() 之间的差异

    • 实际运行时间是t=T(f(n))*c
    • 对于足够大的 n,它会收敛到 t=O(f(n))*c
    • 其中O() 是算法的时间复杂度
    • T() 是任何 n 的实际运行时间方程(不是 O() !!!)
    • c 是一个恒定的时间,需要在所有 fors 中一起处理单次传递等...
    • 更好的O() 并不意味着更快的解决方案
    • 对于任何n 仅在阈值之后
    • O1(f1(n))*c1 < O2(f2(n))*c2
    • 因此,如果您很好地优化了 c 常量,那么您可以将更好的复杂性算法击败到临界点
    • 例如你的代码在T(n.n/2) -> O(n^2)
    • 但是对于低 n 可以比我的 SOE 更快O(n.log(n))
    • 因为我需要准备表格,这需要比您的部门更多的时间
    • 但在那之后你的速度会慢得多......

那么对于最有效的数学和编程解决方案之间是否存在差异的问题

  • 答案是YES它可以在定义的N范围内

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-29
    • 2015-10-09
    • 2013-12-31
    相关资源
    最近更新 更多