【问题标题】:python - Fibonacci Computing Time Differencepython - 斐波那契计算时差
【发布时间】:2016-08-04 11:04:29
【问题描述】:

我编写了以下两个代码来计算斐波那契数列的一个元素。

def fib(n):
    zero, one = 0, 1
    k = 1
    while k < n:
        zero, one = one, zero + one
        k = k + 1
    return one, ls

def fib2(n, memo=None):
    if memo is None:
        memo = {}
    if n == 1 or n == 2:
        return 1
    if n in memo:
        return memo[n]
    else:
        memo[n-1] = fib2(n-1, memo)
        memo[n-2] = fib2(n-2, memo)
        return memo[n-1] + memo[n-2]


##import timeit
##
##print('Fibonacci 1:', timeit.timeit('fib(10000)', '''def fib(n):
##    zero, one = 0, 1
##    k = 1
##    while k < n:
##        zero, one = one, zero + one
##        k = k + 1
##    return one''', number=100))
##
##print('Fibonacci 2:', timeit.timeit('fib2(10000)', '''import sys; sys.setrecursionlimit(10001);
##def fib2(n, memo=None):
##    if memo is None:
##        memo = {}
##    if n == 0 or n == 1:
##        return 1
##    if n in memo:
##        return memo[n]
##    else:
##        memo[n-1] = fib2(n-1, memo)
##        memo[n-2] = fib2(n-2, memo)
##        return memo[n-1] + memo[n-2]''', number=100))

我在fib 中使用了一个简单的while 循环,fib2 是相同的递归实现。但事实证明,fib2 异常缓慢。我想知道为什么会这样。是因为fib2 创建了很多帧吗?我是否正确实现了fib2

谢谢。

【问题讨论】:

  • 这基本上是stackoverflow.com/questions/21710756/…的复制品
  • @ChatterOne 用 Ja​​va 写的。
  • 没关系,区别在于递归和迭代。仔细阅读接受的答案,您会发现编程语言并不重要。
  • 递归通常较慢,因为您已经知道堆栈帧。在 python 等高级语言中很难说多少,但速度较慢。你记忆fib2的方式可能会拖慢你的程序。看看functools中的lru_cache装饰器,而不是自己做memoize(我没有花时间看你是如何memoize的,但如果你做错了,肯定会对速度)。
  • @ChatterOne 他的问题不是专门关于递归与迭代,而是更多的迭代与记忆递归。您链接到的问题一般是关于递归与迭代,但没有提到记忆。

标签: python python-3.x recursion fibonacci


【解决方案1】:

将此简化的递归版本与您的原始迭代解决方案相匹配 - 首先将递归限制提高约 1% 到 10%:

def fib2(n, memo={0: None, 1: 1, 2: 1}):
    if n in memo:
        return memo[n]

    previous = fib2(n - 1)  # implicitly computes fib2(n - 2)

    result = memo[n] = previous + memo[n - 2]

    return result

我没有将memo 作为递归参数传递,因为当默认参数设置为可以修改的结构时,我正在利用“问题”。

上述解决方案比我机器上第一次调用时的原始迭代慢约 4.5 倍——之后,记忆化接管。我们可以通过将我们的“内存”从字典更改为列表来在空间和时间上对此进行一点改进,因为所有键都是顺序整数:

def fib3(n, memo=[None, 1, 1]):
    if n < len(memo):
        return memo[n]

    previous = fib3(n - 1)  # implicitly computes fib3(n - 2)

    result = previous + memo[-2]

    memo.append(result)

    return result

在我的机器上,对于第一次调用,这一次比迭代解决方案慢约 3 倍。但是,我们可以使用递归在速度方面做得更好:

def fib4(n, res=0, nxt=1):
    if n == 0:
        return res
    return fib4(n - 1, nxt, res + nxt)

这仅比迭代解决方案慢约 2 倍,并且/但没有记忆。在具有尾调用优化的语言(即不是 Python)中,这可能会成为/tie 迭代。

【讨论】:

    猜你喜欢
    • 2013-03-31
    • 2016-12-11
    • 2017-07-22
    • 1970-01-01
    • 1970-01-01
    • 2020-01-18
    • 2012-12-03
    • 1970-01-01
    • 2017-12-14
    相关资源
    最近更新 更多