【问题标题】:Which fibonacci function will evaluate faster?哪个斐波那契函数的计算速度更快?
【发布时间】:2013-06-30 01:49:04
【问题描述】:

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

#!/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);

【问题讨论】:

  • 我认为要获得准确的比较,您需要编写一个简单的脚本来回答您的问题。

标签: performance node.js fibonacci


【解决方案1】:

这是一种非常幼稚的计算方式。尝试做类似的事情:

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)

【讨论】:

    【解决方案2】:

    一般而言,递归函数“更干净”且“更容易”编写,但通常需要更多资源(主要是由于堆栈的积累而导致的内存)。在您的情况下,首先获得 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)
    

    【讨论】:

      【解决方案3】:

      递归斐波那契函数的实现方式错误。本文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));
      };
      

      我不太懂语言,所以代码可能有一些问题,但这至少是它的要点。

      【讨论】:

        【解决方案4】:

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

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

        算法很简单:使用分治法求矩阵 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 等等。但是,与其他答案中描述的其他更简单的解决方案相比,使用它没有意义。 (因为纯粹的代码复杂性)

        【讨论】:

          猜你喜欢
          • 2013-03-31
          • 1970-01-01
          • 2012-11-29
          • 1970-01-01
          • 1970-01-01
          • 2020-01-18
          • 2016-08-26
          • 2020-02-12
          相关资源
          最近更新 更多