用于计算Fibonacci序列第n项的最快Java算法?

时间:2012-03-30 17:09:13

标签: java fibonacci

是否知道计算第n个Fibonacci序列的最快Java算法是什么?

我找到了these algorithms。我猜迭代算法应该比递归和分析算法更快。

5 个答案:

答案 0 :(得分:4)

将所有Fibonacci数预先计算到n的足够大的数量,并生成一个源代码片段,用于定义一个数组,该数组的类型可以包含这些数字。

然后,您只需检索数组中索引n中的值即可。这是O(1)。比这快得多。

答案 1 :(得分:2)

试试dynamic programming。创建一个包含第n-1个Fibonacci数的每个值的数组。第一次运行时,它需要与普通的Fibonacci函数一样长,但后续调用可以在O(1)中运行,因为你已经拥有了数组中的值。

答案 2 :(得分:2)

根据我的经验,分析版本在实践中通常非常快,但正如Rosetta代码所说,它只能在序列中的第92个数字上准确。

递归版本需要指数时间才能运行,因此即使对于中等大小的 n ,它也必然非常慢。迭代和尾递归函数在 n 中需要时间线性。可以从Fibonacci序列的matrix form推导出更快的O(lg n )时间算法。

有关递归和尾递归算法的解释,请参阅SICP。

答案 3 :(得分:2)

答案是,像往常一样,“它取决于”。一般来说,你不能真正存储那么多Fibonacci数字,因为它们往往会相当快速地增加 - 事实上,你的链接的分析部分会以指数方式显示它们。

因此,对于大多数实际目的,答案是“不计算 - 缓存”。也就是说,使用查找表。 (通常,在溢出之前,您需要少于100个条目。)

对于传统的存储方法,你不会比递归计算更好,因为它是O(d ^ 2),其中d是输出的位数 - 更复杂的任意大小的数字操作将很难与之竞争。

“分析”可能是较慢的方法之一,因为基础不方便,你将扔掉快速整数数学。

答案 4 :(得分:2)

虽然你确实特别针对Java,但我昨晚在Python 3中看到了不同的实现。特别是,我查看了天真的递归实现和分析实现(然而我称之为封闭形式)。这是代码,没有我的单元测试:

import math
from timeit import Timer

def fib_recursive(n):
    """
        Compute the Fibonacci sequence from a given number n
    """
    if n < 2:
        return n
    else:
        return fib_recursive(n - 2) + fib_recursive(n - 1)

def fib_closed_form(n):
    """
        Compute the Fibonacci sequence using a closed form.
    """
    def calc_golden_ratio():
        return (1 + math.sqrt(5)) / 2

    gr = calc_golden_ratio()
    inverse_gr = 1 - gr
    numerator = math.pow(gr,  n) - math.pow(inverse_gr,  n)
    return numerator // math.sqrt(5)

if __name__ == '__main__':
    for n in range(0,  10):
        n = str(n)
        time = Timer("fib_closed_form(" + n + ")",  "from __main__ import fib_closed_form")
        print('Fib_Closed_Form(' + n +') = ' + str(time.timeit()))
        time = Timer("fib_recursive(" + n + ")",  "from __main__ import fib_recursive")
        print('Fib_Recursive(' + n +') = ' + str(time.timeit()))

以下是值为1-10的函数的时序(时间以秒为单位,使用timeit模块测量)。默认情况下,每个调用由timeit模块进行1000000次,因此它是所有调用总计所需的时间的结果:

Python 3.2.2 (default, Nov 21 2011, 16:50:59) 
[GCC 4.6.2] on staggerlee, Standard
>>> 
Fib_Closed_Form(1) = 5.808775901794434
Fib_Recursive(1) = 0.6938691139221191

Fib_Closed_Form(2) = 6.142783880233765
Fib_Recursive(2) = 1.9276459217071533

Fib_Closed_Form(3) = 6.62189793586731
Fib_Recursive(3) = 3.6403379440307617

Fib_Closed_Form(4) = 6.376585960388184
Fib_Recursive(4) = 6.733421802520752

Fib_Closed_Form(5) = 6.566863059997559
Fib_Recursive(5) = 11.409136056900024

Fib_Closed_Form(6) = 6.521269083023071
Fib_Recursive(6) = 18.514809131622314

...

Fib_Closed_Form(10) = 6.631903886795044
Fib_Recursive(10) = 131.51839208602905

正如您所看到的,封闭形式具有更高的前期成本。递归的一个把它吹出水面!它只能通过n = 4的值保持竞争力。你可以看到它的时间越来越差。当我们达到n = 6左右时,我们已经看到这不是正确的方向。

顺便说一下,我昨晚尝试了n = 25。封闭的表格花了大约相同的时间,递归表格在我上床睡觉前没有完成(至少运行半小时)。

我的观点是,这些实现起来相当容易,并且可以直接进行一些单元测试。您可以尝试一下并在Java中查看自己的结果,尽管使用Java等语言的时序可能很复杂而无需额外的设置。