如何通过递归找到fibonancci系列

时间:2016-06-02 15:33:03

标签: python python-2.7 python-3.x recursion

为了找到斐波那契系列,我写下这段代码:

def fib(n):
    if n ==1 or n ==0:
        return 1
    else:
        return fib(n-1) + fib(n-2)

这绝对没问题。但我的问题是,如果我通过fib(5)调用fib()然后计算值fib(2)多少次?怎么样?

抱歉这个愚蠢的问题,我是编程的新手

6 个答案:

答案 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个步骤,

将是:

  1. (n-1,n-2)

  2. (n-2,n-3),(n-3,n-4)

  3. (n-3,n-4),(n-4,n-5),(n-4,n-5),(n-5,n-6)

    < / LI>

    等等。