fibnacci数列递归算法及改进

fibnacci数列1,1,2,3,5,8,13,21...,数列第一项和第二项等于1,从第三项开始开始,每一项都等于前两项之和,简单的用数学公式表示:

n=0或n=1时,f(n)=1;

n>1时,f(n) = f(n-1) + f(n-2)

可以看出使用递归算法可解决该问题,python代码如下:

def fibnacci_I(x):
    if x < 0:
        return 0
    if x == 0 or x == 1:
        return 1
    return fibnacci_I(x-1) + fibnacci_I(x-2)

执行fibnacci_I(20),结果为10946。似乎一切正常。但是当x的值很大时,程序会出现运行错误:RuntimeError: maximum recursion depth exceeded,最大递归深度溢出,这是因为python中递归深度大于等于1000时就会报错。即使python不做限制,当x很大时,程序需要耗费很长的时间才能计算完成,这里就涉及到linux堆栈的问题。因为linux系统为计算机分配的堆栈大小有限制(使用ulimit -a可查看堆栈大小),而程序运行时会将程序放入堆栈,每调用一次递归就会分配一次堆栈,一个堆栈的大小为8K,我的虚拟机的堆栈大小为8092k,可以看出很快就会把堆栈用尽,所以时间复杂度就很大。该算法的时间复杂度为O(2^n)。

仔细看fibnacci数列,可以发现有很多重复运算,比如f(5) = f(4) + f(3);f(4) = f(3) + f(2);这里对f(3)做了重复计算,那么可以对算法做改进,将重复的计算结果缓存起来,用空间来换取时间。改进后的程序代码如下:

cache = {0:1,1:1}
def fibnacci_II(x):
    global cache
    if x < 0:
        return 0
    if x == 0 or x == 1:
        return 1
    if x in cache:
        return cache[x]
    result = fibnacci_II(x-1) + fibnacci_II(x-2)
    if x not in cache:
        cache[x] = result
    return result

实际运行一下可以看出改进后的程序比原有程序效率高很多。因为对中间结果做了保存,所以实际上是用空间来换取时间。

似乎已经很好了,还有更好的解法吗?答案是肯定的,使用循环可将算法改进为非递归算法,因为f(x) = f(x-1) + f(x-2),那么我们可以在计算f(x-1)和f(x-2)时将结果保存下来,那么计算f(x)的时候就可以直接得到结果了,依次类推,可以用一个for循环解决。该算法的代码如下:

def fibnacci_III(x):
    if x < 0:
        return 1
    if x == 0 or x == 1:
        return 1
    result = 0
    a = 1
    b = 1
    for i in xrange(x):
        if i > 1:
            result = a + b
            a = b
            b = result
    return a + b
总结,递归算法的特点是清晰明了,但是递归算法的时间复杂度很大,意味着计算时间会很长,而改为非递归算法后,可以很好的减少时间复杂度。写程序时应该尽量避免递归,将递归算法改为非递归算法。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值