最近开始学习算法导论相关知识,了解到Fibonacci数列的不同实现,所以用java语言实现并进行测试,发现矩阵方式和从下向上计算(f(0),f(1),…, f(n))性能远远高于递归方式。
备注:可能代码质量不高,主要为了说明问题。其中没有对输入的Number采用更严谨的验证。
package com.demo;
import java.util.Date;
public class FibonacciNumbers {
/**
* @param number
* 最简单的递归调用,复杂度a^n,a为黄金分割点
* @return
*/
public static long Fibonacci(int number) {
if (number == 0)
return 0;
if (number == 1)
return 1;
if (number >= 2)
return Fibonacci(number - 1) + Fibonacci(number - 2);
return -1;
}
/**
* @param number
* 时间复杂度为O(n) bottom algorithm
* compute F(0), F(1), ..., F(N)
* @return
*/
public static long Fibonacci2(int number) {
long[] result = new long[number + 1];
if (number == 0)
return 0;
if (number == 1)
return 1;
if (number >= 2) {
result[0] = 0;
result[1] = 1;
for (int i = 2; i <= number; i++) {
result[i] = result[i - 1] + result[i - 2];
}
}
return result[number];
}
/**
* @param number >= 1
* 时间复杂度为O(logn)
* thm:[f(n+1), f(n); f(n), f(n-1)] = [1, 1; 1 0]^n
* @return
*/
// private static long[][] prime = {{1, 1} ,{1, 0}};
public static long Fibonacci3(int number) {
Element result = FibonacciKernel(number);
if ( result != null) {
return result.b;
}
return -1;
}
public static Element FibonacciKernel(int number) {
if (number == 1) {
return new Element(1,1,1,0);
}
if (number >= 2) {
if (number % 2 == 0) {
Element e = FibonacciKernel(number/2);
// 为了访问方便,设置为共有属性
long a = e.a*e.a + e.b*e.c;
long b = e.a*e.b + e.b*e.d;
long c = e.c*e.a + e.d*e.c;
long d = e.c*e.b + e.d*e.d;
return new Element(a, b, c, d);
} else {
Element e = FibonacciKernel((number-1)/2);
long a = e.a*e.a + e.b*e.c;
long b = e.a*e.b + e.b*e.d;
long c = e.c*e.a + e.d*e.c;
long d = e.c*e.b + e.d*e.d;
// e*e*prime[1, 1; 1 0]
return new Element(a+b, a, c+d, c);
}
}
return null;
}
public static void main(String[] args) {
Date d1 = new Date();
System.out.println("45的递归算法结果: " + Fibonacci(45));
Date d2 = new Date();
System.out.println("总共消耗" + (d2.getTime() - d1.getTime()) + "ms");
System.out.println("45的非递归算法结果: " + Fibonacci2(45));
Date d3 = new Date();
System.out.println("总共消耗" + (d3.getTime() - d2.getTime()) + "ms");
System.out.println("45的矩阵方式计算结果: " + Fibonacci3(45));
Date d4 = new Date();
System.out.println("总共消耗" + (d4.getTime() - d3.getTime()) + "ms");
}
}
class Element {
long a;
long b;
long c;
long d;
public Element(long a, long b, long c, long d) {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
}
public Element() {
}
}
经过测试:
45的递归算法结果: 1134903170
总共消耗19591ms
45的非递归算法结果: 1134903170
总共消耗0ms
45的矩阵方式计算结果: 1134903170
总共消耗0ms
发现后两种方式结果一样,但是理论上矩阵方式还是比非递归方式性能更高。