哪个斐波纳契函数会更快评估?

时间:2013-07-02 15:43:23

标签: performance node.js fibonacci

我正在尝试将前100个斐波那契数字输出到.txt文件。我让它运行,但它需要一段时间。斐波那契或斐波纳契2会更快吗?下面的代码使用第一个。

#!/usr/bin/env node

var fs = require('fs');

// Fibonacci
// http://en.wikipedia.org/wiki/Fibonacci_number
var fibonacci = function(n) {
    if(n < 1) { return 0;}
    else if(n == 1 || n == 2) { return 1;}
    else if(n > 2) { return fibonacci(n - 1) + fibonacci(n - 2);}
};

// Fibonacci: closed form expression
// http://en.wikipedia.org/wiki/Golden_ratio#Relationship_to_Fibonacci_sequence
var fibonacci2 = function(n) {
    var phi = (1 + Math.sqrt(5))/2;
    return Math.round((Math.pow(phi, n) - Math.pow(1-phi, n))/Math.sqrt(5));
};

// Find first K Fibonacci numbers via basic for loop
var firstkfib = function(k) {
    var i = 1;
    var arr = [];
    for(i = 1; i < k+1; i++) {
        var fibi = fibonacci(i);
        arr.push(fibi);

        // Print to console so I can monitor progress
        console.log(i + " : " + fibi); 
    }
    return arr;
};

var fmt = function(arr) {
    return arr.join(",");
};

var k = 100;

// write to file
var outfile = "fibonacci.txt";
var out = fmt(firstkfib(k));
fs.writeFileSync(outfile, out);
console.log("\nScript: " + __filename + "\nWrote: " + out + "\nTo: " + outfile);

4 个答案:

答案 0 :(得分:1)

通常,递归函数“更清晰”,“更容易”编写,但通常需要更多的资源(主要是由于堆栈的累积而导致的内存)。在你的情况下,首先获得100的最佳方法是使用一个简单的循环来编程,该循环将计算下一个斐波那契数列并将其添加到列表中。

double a[100];
a[0] = 1;
a[1] = 1;
K=2;
Do{ 

{
 a[k] = a[k - 2] + a[k- 1];
 k++;
}While (k!=100)

答案 1 :(得分:1)

递归的斐波纳契函数以错误的方式实现。本文Recursion and Fibonacci Numbers讨论了递归实现它的正确方法。对于那些懒得阅读的人来说,这是他们的代码(它在C中,但翻译起来不应该太难):

unsigned long fib(unsigned int n)
{
  return n == 0 ? 0 : fib2(n, 0, 1);
}

unsigned long fib2(unsigned int n, unsigned long p0, unsigned long p1)
{
  return n == 1 ? p1 : fib2(n - 1, p1, p0 + p1);
}

更高效的实现会在计算斐波纳契序列时缓存它们的值:

var cache = [];

var fibonacci = function(n) {
  if(cache.length > n) return cache[n];
  return (cache[n] = fib2(n, 0, 1));
};

var fib2 = function(n, p0, p1) {
  if(cache.length > n) return cache[n];
  return n == 1 ? p1 : (cache[n] = fib2(n - 1, p1, p0 + p1));
};

我真的不懂语言,因此代码可能存在一些问题,但这至少是它的要点。

答案 2 :(得分:1)

对于你的问题,我们不能比O(n)做得更好,因为你需要产生所有前n个(n = 100)数。

有趣的是,如果你只需要第n个fib数,那么也存在一个O(log n)解决方案。

算法很简单:使用Divide and Conquer方法找出矩阵A的n次方并报告第(0,0)个元素,其中

 A = |1     1 |
     |1     0 |

递归

 A^n = A^(n/2) * A^(n/2)

时间复杂度:

T(n) = T(n/2) + O(1) = O(logn)

如果你用一张纸来考虑它,你会发现证据很简单并且基于归纳原理。 如果您仍需要帮助,请参阅this link

注意:当然你可以迭代计算A,A ^ 2,A ^ 3等等。但是,与其他答案中描述的其他更简单的解决方案相比,使用它是没有意义的。 (由于纯粹的代码复杂性)

答案 3 :(得分:0)

这是一种非常天真的计算方法。尝试做类似的事情:

long[] a = new long[100];
a[0] = 1;
a[1] = 1;
for (int i = 2; i < 100; ++i)
{
    a[i] = a[i - 2] + a[i - 1];
}

for (int i = 0; i < 100; ++i)
Console.WriteLine(a[i]);

这样你就得到一个线性时间O(n)