前几天有人对我说,递归会比迭代更好,如果可能的话,应该总是使用。
所以,我进入递归并尝试编写一个简单的程序来获得数字的阶乘。这是递归:
def fact(n):
if n == 1:
return 1
return n * fact(n - 1)
虽然这种方法很好,但只要RuntimeError: maximum recursion depth exceeded
达到997以上就会得到n
。
所以我编写了一个完全相同的简单函数,但使用for loop
。
def fact(n):
a = 1
for x in range (0, n, 1):
a = a * (n - x)
return a
虽然n < 10000
在150毫秒内给出答案。
所以,我可能会因为数字较少而递归速度更快,但是没有。这需要更长时间:
所以我的问题是:
在用Python编写程序时是否有任何理由使用递归?
和:
是否有任何问题只能通过递归来解决?
答案 0 :(得分:5)
没有问题需要通过显式递归来解决;并且没有任何问题需要通过显式迭代来解决 - Church and Turing have proved它们是可以互换的。
然而,有些问题有更简洁的代码,如果使用递归则更容易推理。实际上,Python标准库甚至C代码本身在许多地方内部使用递归,因此很容易在许多地方遇到可怕的递归限制,例如打印repr
嵌套元组:
>>> from functools import reduce
>>> x = reduce(lambda x, y: (x,), range(10000))
>>> x # recursion limit hit in C code
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: maximum recursion depth exceeded while getting the repr of a tuple
>>> import pprint
>>> pprint.pprint(x) # recursion limit hit in Python standard library code.
Traceback (most recent call last):
...
File "/usr/lib/python3.4/pprint.py", line 390, in _safe_repr
orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
File "/usr/lib/python3.4/pprint.py", line 340, in _safe_repr
if issubclass(typ, dict) and r is dict.__repr__:
RuntimeError: maximum recursion depth exceeded while calling a Python object
您总是可以将递归算法转换为具有状态机和中间参数堆栈的迭代,因为毕竟这非常适合CPU实现递归。
答案 1 :(得分:2)
我无法分辨哪个更快,但递归肯定在编程中占有一席之地。例如,考虑以下函数,该函数应该被压平&#34;嵌套列表,成为一个很棒的大清单:
def expand_list(lst):
result = []
for element in lst:
if isinstance(element, list):
result += expand_list(element)
else:
result.append(element)
return result
(例如expand_list([1,2,3,[4,5,[6,7]]])
评估为[1,2,3,4,5,6,7]
)
迭代无法很好地处理这个问题。
(旁注:Python中的函数与上面的函数一样 - 这只是一个例子。)
答案 2 :(得分:1)
迭代通常(在这种情况下)也更有效(性能明智,假设您正在执行类似的操作)。递归具有更多的开销,因为每次都需要进行新的函数调用,这会花费资源。
https://en.wikipedia.org/wiki/Recursion_(computer_science)说
&#34;递归的力量显然在于定义的可能性 有限陈述的一组无限的对象&#34;
但是用例必须非常具体,因为递归才是更好的选择。
关于错误,Python有一个内置函数,它返回最大递归深度,如果你觉得这很有用:https://docs.python.org/2/library/sys.html#sys.getrecursionlimit