关于斐波那契数列的3种解法

1.斐波那契

关于斐波那契数列的定义和应用网上已经有一大堆介绍了,可以去查一查。我以前只知道用循环和递归这两种方式求,但是最近发现一种矩阵乘方的方式来求解。因此就用C语言实现了这3中方式。

#include <stdio.h>
#include <stdlib.h>

// 求斐波那契第n个数,循环
long long offer74_fibonacci0(unsigned n)
{
  if (n <= 1)
    return n;
  long long f0 = 0,f1 = 1, fn;
  while (--n)
  {
    fn = f0 + f1;
    f0 = f1;
    f1 = fn;
  }
  return fn;
}

// 求斐波那契第n个数,递归(n大了后会有很多重复运算,不推荐)
long long offer74_fibonacci1(unsigned n)
{
  return n <= 1 ? n : offer74_fibonacci1(n-1)+offer74_fibonacci1(n-2);
}

//-----------------------------------------------
// 矩阵乘方的计算方式
typedef struct Matrix2By2_t
{
  long long m00,m01,m10,m11;
} Matrix2By2;

// 初始化一个矩阵
Matrix2By2 *InitMatrix(long long m00,long long m01,long long m10,long long m11)
{
  Matrix2By2 *matrix = (Matrix2By2*)malloc(sizeof(Matrix2By2));
  if (NULL == matrix)
    exit(-1);

  matrix->m00 = m00;
  matrix->m01 = m01;
  matrix->m10 = m10;
  matrix->m11 = m11;
  return matrix;
}

// 2个矩阵相乘,释放内存时注意2个矩阵相同的情况
Matrix2By2 *MatrixMultiply(Matrix2By2 *matrix1,Matrix2By2 *matrix2)
{
  Matrix2By2 *tmp = (Matrix2By2*)malloc(sizeof(Matrix2By2));
  if (NULL == tmp)
    exit(-1);

  tmp->m00 = matrix1->m00 * matrix2->m00 + matrix1->m01 * matrix2->m10;
  tmp->m01 = matrix1->m00 * matrix2->m01 + matrix1->m01 * matrix2->m11;
  tmp->m10 = matrix1->m10 * matrix2->m00 + matrix1->m11 * matrix2->m10;
  tmp->m11 = matrix1->m10 * matrix2->m01 + matrix1->m11 * matrix2->m11;

  if (NULL != matrix1)
    free(matrix1);
  if (matrix1 != matrix2 && NULL != matrix2)
    free(matrix2);
  matrix1 = NULL;
  matrix2 = NULL;
  return tmp;
}

// 计算斐波那契结果
Matrix2By2 *MatrixPower(unsigned n)
{
  if (n <= 0)
    exit(-1);

  Matrix2By2 *matrix;
  if (n == 1)
  {
    matrix = InitMatrix(1,1,1,0);
  }
  else if (n%2 == 0)
  {
    matrix = MatrixPower(n/2);
    matrix = MatrixMultiply(matrix, matrix);
  }
  else if (n%2 == 1)
  {
    matrix = MatrixPower((n-1)/2);
    matrix = MatrixMultiply(matrix, matrix);
    matrix = MatrixMultiply(matrix, InitMatrix(1,1,1,0));
  }

  return matrix;
}

// 矩阵法计算
long long offer74_fibonacci2(unsigned n)
{
  if (n <= 1)
    return n;

  Matrix2By2 *tmp = MatrixPower(n - 1);
  long long r = tmp->m00;
  if (NULL != tmp)
    free(tmp);
  return r;
}

// 打印函数
void offer74_fibonacci_print(const char *topic, unsigned n, long long f(unsigned))
{
  printf("%s : ", topic);
  for (unsigned i = 0; i < n; ++i)
  {
    printf("%lld,", f(i));
  }
  printf("\n");
}

void main(void)
{
  unsigned n = 20;

  offer74_fibonacci_print("fibonacci0", n, offer74_fibonacci0);
  offer74_fibonacci_print("fibonacci1", n, offer74_fibonacci1);
  offer74_fibonacci_print("fibonacci2", n, offer74_fibonacci2);
}
2.总结

看了上述代码可以发现,递归最简洁,但是计算过程中会存在大量重复计算,如果求比较大的数时栈内存会消耗比较大。循环的方法是比较容易想到的,但是这种算法的时间复杂度是O(n),矩阵乘方的方式时间复杂度只有O(logN)。以上就是这3中方式的优缺点。

captcha