Python 递归调用的流程
我在寻找这个问题的答案,但大多数答案都是用Python以外的编程语言给出的Python 递归调用的流程,python,python-2.7,recursion,Python,Python 2.7,Recursion,我在寻找这个问题的答案,但大多数答案都是用Python以外的编程语言给出的 现在在这段代码中: def f(n): if n==0: return 1 else: m = f(n-1) s = n * m return s 我知道,如果我使用n=3,函数将使用第二个分支来计算“3-1=2”,然后移动到与“2-1=1”相同的位置,最后返回0,然后
现在在这段代码中:
def f(n):
if n==0:
return 1
else:
m = f(n-1)
s = n * m
return s
我知道,如果我使用n=3,函数将使用第二个分支来计算“3-1=2”,然后移动到与“2-1=1”相同的位置,最后返回0,然后返回结果现在,在以下情况下会发生什么:
def fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fibonacci(n-1) + fibonacci(n-2)
假设我们用n=5执行它。然后使用第三个分支返回fib(4)+fib(3)。那又怎样呢?程序将使用哪个数字作为n、4或3的新值?
谢谢。作为参数给定的递归级别将调用自身两次,一次调用
4
,一次调用3
,这两次调用的结果将相加
类似地,使用4
调用它将导致两个调用,一个调用3
,另一个调用2
。从各个层次往下看。所以递归“树”应该是:
_____5_____
/ \
__4__ 3
/ \ / \
3 2 2 1
/ \ / \ / \
2 1 1 0 1 0
/ \
1 0
您更“经典”的递归(如阶乘)在每个级别只调用自己一次,但这并不是递归的必要条件:
5
\
4
\
3
\
2
\
1
如果要查看发生了什么,请将其更改为以下内容:
def fibonacci(x, n):
for i in range(x):
print " ",
print "Level %d called with %d"%(x,n)
if n == 0:
return 0
if n == 1:
return 1
return fibonacci(x+1,n-1) + fibonacci(x+1,n-2)
print fibonacci (0,5)
生成的输出:
Level 0 called with 5
Level 1 called with 4
Level 2 called with 3
Level 3 called with 2
Level 4 called with 1
Level 4 called with 0
Level 3 called with 1
Level 2 called with 2
Level 3 called with 1
Level 3 called with 0
Level 1 called with 3
Level 2 called with 2
Level 3 called with 1
Level 3 called with 0
Level 2 called with 1
5
你会看到,我还删除了一些人使用的完全不必要的“返回后其他”范式。它很少需要,而且会降低代码的可读性
在解释了这一点之后,您还应该意识到递归可能被滥用的情况。尽管斐波那契序列可以优雅地编码为递归解决方案,但它并不十分有效,因为它在每个分支中重新计算了许多不同的值(例如,在给定的示例中,
fib(2)
计算了三次,如果使用比5
更大的参数调用它,则计算次数要多得多)
即使是阶乘也不太适合递归,因为它会缓慢地减少“搜索空间”:fact(20)
实际上会在堆栈上深入二十层,而堆栈通常是有限的资源
最好的递归算法是那些能够快速减少搜索空间的算法,例如二进制搜索,它在每个递归级别上将搜索空间减半
知道何时使用递归通常比知道如何使用递归同样重要
您可以使用阶乘和斐波那契的迭代解决方案,如下所示:
def fact (n): # n = 1..whatever
result = n
for i in range (2,n):
result = result * n
def fib(n): # n = 1..whatever
me = 1
if n >1:
grandparent = 1
parent = 1;
for i in range(2, n):
me = parent + grandparent
grandparent = parent
parent = me
return me
这两种方法都不会因为大量的
n
而耗尽堆栈。在生成斐波那契数方面,您最好不要使用递归。非常感谢。我希望我能投票赞成你的答案。唉,我需要15个代表点才能做到这一点。@Quester,作为问题的提问者,你应该接受(使用绿色勾号)回答问题的最佳答案,并向那些有帮助的人投票(如果可以的话)。我很确定你总是可以接受的,尽管我已经有一段时间没有担任代表级别了:-)