为了找到斐波那契系列,我写下这段代码:
def fib(n):
if n ==1 or n ==0:
return 1
else:
return fib(n-1) + fib(n-2)
这绝对没问题。但我的问题是,如果我通过fib(5)调用fib()然后计算值fib(2)多少次?怎么样?
抱歉这个愚蠢的问题,我是编程的新手
答案 0 :(得分:1)
正如评论中提到的polku,它很简单,可以看到你的函数被调用了多少次:
def fib(n):
print('Called fib({})'.format(n))
if n ==1 or n ==0:
return 1
else:
return fib(n-1) + fib(n-2)
>>> fib(5)
Called fib(5)
Called fib(4)
Called fib(3)
Called fib(2)
Called fib(1)
Called fib(0)
Called fib(1)
Called fib(2)
Called fib(1)
Called fib(0)
Called fib(3)
Called fib(2)
Called fib(1)
Called fib(0)
Called fib(1)
8
你的函数对之前的任何一个运行都不知道,所以每当你问它一个特定的值(0或1除外)时,它必须重新计算它。如果要避免这种情况,可以使用名为 memoization 的过程。在Python中执行此操作的一种简单方法是利用常见的新手问题the mutable default argument:
def fib2(n, memo=[1, 1]):
print('Called fib2({})'.format(n))
if len(memo) > n:
print(' I already know this one!')
return memo[n]
else:
memo.append(fib2(n-1) + fib2(n-2))
return memo[-1]
>>> fib2(5)
Called fib2(5)
Called fib2(4)
Called fib2(3)
Called fib2(2)
Called fib2(1)
I already know this one!
Called fib2(0)
I already know this one!
Called fib2(1)
I already know this one!
Called fib2(2)
I already know this one!
Called fib2(3)
I already know this one!
8
该函数的每次调用都使用相同的memo
列表对象,因此在一次调用中将其附加到将来的调用中。
答案 1 :(得分:1)
您可以使用列表和词组等可变类型
dict_counts = {}
def fib(n,d):
v = d.get(n,0)
d[n]=v+1
if n ==1 or n ==0:
return 1
else:
return fib(n-1,d) + fib(n-2,d)
fib(5, dict_counts)
print "all counts: ", dict_counts
print "count of f(2) = ", dict_counts.get(2, 0)
输出:
all counts: {0: 3, 1: 5, 2: 3, 3: 2, 4: 1, 5: 1}
count of f(2) = 3
dict是一个可变对象,因此您可以更改函数内部的dict值并访问函数外部的更改。
答案 2 :(得分:0)
如果我调用fib(5)那么它计算值fib(2)多少次?
三。如果添加打印声明,您可以自己查看。
def fib(n):
if n == 1 or n == 0:
return 1
else:
print('Computing fib(%i)...' % n)
return fib(n-1) + fib(n-2)
输出将如下所示:
In [4]: fib(5)
Computing fib(5)...
Computing fib(4)...
Computing fib(3)...
Computing fib(2)...
Computing fib(2)...
Computing fib(3)...
Computing fib(2)...
Out[4]: 8
这也让你了解递归的内部结构。
要弄明白fib(5)
,必须return fib(n-1) + fib(n-2)
,即fib(4) - fib(3)
。它必须先计算fib(4)
。
要弄明白fib(4)
,需要fib(3)
和fib(2)
。它首先fib(3)
。
要弄明白fib(3)
,它会fib(2)
和fib(1)
。它首先fib(2)
。
要弄明白fib(2)
,需要fib(1)
和fib(0)
。它首先fib(1)
。
最后,我们返回没有其他函数调用! fib(1)
为我们提供了一个整数1,我们可以返回添加到fib(0)
,它也会立即返回1.
该添加完成了fib(2)
的返回。请记住,此调用是计算fib(3)
的一部分,所以现在我们需要添加的后半部分。它是fib(1)
所以我们立即返回并完成通话。
然后我们可以找出fib(3)
的后半部分,这意味着我们再次计算fib(2)
。这两个部分立即返回,我们得到答案。
现在我们退回fib(4)
。它的第一部分已经返回,所以我们需要计算下一半,fib(3)
。这与以前完全一样。
希望现在Computing fib(n)...
的堆栈更有意义。 :)
答案 3 :(得分:0)
fib(2)
计算3次:
>>> fib(5)
computing fib(5)
computing fib(4)
computing fib(3)
computing fib(2)
computing fib(2)
computing fib(3)
computing fib(2)
8
为了避免这种重复的工作,您可以采用迭代方法来计算 n 的斐波那契数,或者在递归的同时实现memoization。
答案 4 :(得分:0)
计算每个数字不止一次,而python在递归时非常周 如果你传递5到你的递归代码,它将计算5倍fib(1),3倍fib(2),2倍fib(3)和1时间fib(4)/ fib(5)
更快找到fib
的方法def fib(n):
... a, b = 0, 1
... for _ in xrange(n):
... a, b = b, a+b
... return a
答案 5 :(得分:0)
避免重新计算的另一种方法是使用动态编程。您可以在列表中保存一次计算的金额,并且每次要计算某些内容时,请先在列表中查找。如果你有它,你将不会再次调用该功能。 您还可以在访问该列表时放置一个计数器,以查明它访问该计数器的次数。 绘制执行树也可以提供帮助:
对于n个步骤,将是:
(n-1,n-2)
(n-2,n-3),(n-3,n-4)
(n-3,n-4),(n-4,n-5),(n-4,n-5),(n-5,n-6)
< / LI> 醇>等等。