听说学院因为有几个所谓推免研究生因为知道面试时候要考上机学程序而没去大发雷霆,题目是Fibonacci数列的递归求解。我翻了下书,把我知道的求解过程写下来:
方法一:
最普通的递归算法求解,是最容易理解的:
unsigned long fibonacci_normal(int n){
int result;
if( n == 1 || n == 2)
return 1;
result = fibonacci_normal(n - 1) + fibonacci_normal(n - 2);
return result;
}
方法二:
非递归求解,最容易想到的方法:也就是三个变量,一个循环就可以搞定:
unsigned long fibonacci(int n)
{
unsigned long f0, f1, result;
int i;
if(n <= 2 )
return 1;
for(f0 = 1, f1 = 1, i = 3; i <= n; i++)
{
result = f0 + f1;
f0 = f1;
f1 = result;
}
return result;
}
方法三:
上次上算法的老师讲分治法的时候貌似有提到过Fibonacci的求解,没怎么留意,只是感觉他说的方法就是上面的方法二,用非递归的方求解。这次翻了下书,才明白,非也!书上用到的是矩阵的乘法来做的:
也就是用[1, 1 | 1, 0]这样一个2*2的矩阵(第一行是1和1第二行是1和0,由于不好表示就这样表示了)来乘以[f(n-1) | f(n-2)]这样的矩阵得到的就是[f(n) | f(n-1)],这种方法的好处就是能够将加法专为求矩阵的n次方,这样的话就可以很好的利用下面的公式了
单位矩阵 n = 0
M n = M k 2 n = 2k(也就m的n次方是m的k次方的平方,不好表示,图方便 ^_^)
M*(M 2k) n = 2k+1(也就m的n次方是m的k次方的平方再乘以m)
这样的话,每次都是将问题分解为其原来问题的一般,所需要的计算次数也就大大减少,当然要看其详细的算法的时间复杂度分析,请参照具《C语言名题精选百则》,我是参照上面讲的。
有了上面的分析,以及参照M的等式,就可以很容易的写出其递归解,只不过其递归解是建立在分治法的基础上的;如下所示:
void matrix_power(unsigned long a, unsigned long b, unsigned c, unsigned d, int n,
unsigned long* aa, unsigned long* bb, unsigned long* cc, unsigned* dd){
unsigned long xa, xb, xc, xd;
if(n == 1){
*aa = a, *bb = b, *cc = c, *dd = d;
}else if(n & 0x01 == 1){
matrix_power(a, b, c, d, n - 1, &xa, &xb, &xc, &xd);
*aa = a*xa + b*xc;
*bb = a*xb + b*xd;
*cc = c*xa + d*xc;
*dd = c*xb + d*xd;
}else{
matrix_power(a, b, c, d, n>>1, &xa, &xb, &xc, &xd);
*aa = xa*xa + xb*xc;
*bb = xa*xb + xb*xd;
*cc = xc*xa + xd*xc;
*dd = xc*xb + xd*xd;
}
}
unsigned long fibonacci_matrix(int n){
unsigned long a, b, c, d;
if(n == 1 || n == 2)
return 1;
else{
matrix_power(1, 1, 1, 0, (n - 2), &a, &b, &c, &d);
return (a + b);
}
}
上面的方法算法复杂度较前面的非递归算法的复杂度大,但是根据其算法复杂度的分析,其是在当n达到一定值的时候,其执行的速度会比用非递归算法更高
由于unsigned long 所表示的范围有限,我也不能把其中的n设置得很到来测试,我只是在n=50的情况下,在Linux下面用Time命令测试了下,其结果如下:
# time ./FIB
fibonacci(50) = 3996334433
real 0m0.019s
user 0m0.000s
sys 0m0.012s
# time ./FIB
fibonacci(50) = 3996334433
real 0m0.020s
user 0m0.000s
sys 0m0.008s
# time ./FIB_M
fibonacci_matrix(50) = 3996334433
real 0m0.017s
user 0m0.000s
sys 0m0.012s
# time ./FIB_M
fibonacci_matrix(50) = 3996334433
real 0m0.016s
user 0m0.000s
sys 0m0.008s
(注:FIB---非递归算法 FIB_M---基于分治法的递归算法)
从上面没,看不出有多大大差别。但是能够通过矩阵将其与分治法联系起来,觉得不错。
所以写下来,供以后参考