我使用以下代码解决了项目Euler的问题10,该代码通过强力实施:
def isPrime(n):
for x in range(2, int(n**0.5)+1):
if n % x == 0:
return False
return True
def primeList(n):
primes = []
for i in range(2,n):
if isPrime(i):
primes.append(i)
return primes
def sumPrimes(primelist):
prime_sum = sum(primelist)
return prime_sum
print (sumPrimes(primeList(2000000)))
这三个功能的工作原理如下:
然后我编写了一个新函数 primeListRec ,它与 primeList 完全相同,以帮助我更好地理解递归:
def primeListRec(i, n):
primes = []
#print i
if (i != n):
primes.extend(primeListRec(i+1,n))
if (isPrime(i)):
primes.append(i)
return primes
return primes
上述递归函数有效,但仅适用于非常小的值,如'500'。当我输入'1000'时,该功能导致我的程序崩溃。当我输入类似'2000'的值时,Python给了我这个:
RuntimeError:超出最大递归深度。
我的递归函数出了什么问题?或者是否有一些特定的方法来避免递归限制?
答案 0 :(得分:28)
递归不是在Python中执行操作的最惯用的方式,因为它没有tail recursion优化,因此使用递归作为迭代的替代是不切实际的(即使在您的示例中函数不是尾递归,无论如何都无济于事。基本上,这意味着如果你希望你的输入很大,你就不应该把它用于复杂度大于线性的东西(对于那些具有对数递归深度的事情来说,这仍然是可以的,比如像QuickSort那样划分和征服算法)。
如果您想尝试这种方法,请使用更适合进行函数式编程的语言,如Lisp,Scheme,Haskell,OCaml等;或尝试使用Stackless Python,它在堆栈使用方面有更广泛的限制,并且还具有尾递归优化: - )
顺便说一下,函数的尾递归等价物可能是:
def primeList(n, i=2, acc=None):
return i > n and (acc or []) or primeList(n, i+1, (acc or []) + (isPrime(i) and [i] or []))
另一个“顺便说一句”,你不应该构建一个列表,如果你只是为了将值加起来......解决Project Euler第10个问题的Pythonic方法是:
print sum(n for n in xrange(2, 2000001) if all(n % i for i in xrange(2, int(n**0.5)+1)))
(好吧,也许在不同的行中拆分它会更加Pythonic,但我喜欢一个衬里^ _ ^)
答案 1 :(得分:1)
嗯,我不是python专家,但我认为你已达到stack限制。这就是递归的问题,当你不必递归很多次但当递归次数达到相当大的时候没有好处时,这很好。
理想的替代方法是重写算法以改为使用迭代。
修改:实际上,通过更改sys.getrecursionlimit,您可以更仔细地查看特定错误。那只会带你到目前为止。最终你会得到一个stackoverflow异常,它让我回到原点。
答案 2 :(得分:1)
就像已经说过的那样,在无法处理深层堆栈的语言中,采用迭代方法会更好。特别是在您的情况下,最好更改使用的算法。我建议使用Sieve of Eratosthenes来查找素数列表。它会比你当前的程序快得多。
答案 3 :(得分:0)
您正在迭代n个数字并在每个步骤中递归。因此,Python的递归限制定义了您的最大输入数。这显然是不可取的。特别是因为欧拉问题通常涉及相当大的数字。
答案 4 :(得分:-2)
你可以用脏的方式做到这一点:
try: function() except: function()