關於斐波那契數列的3種解法


1.斐波那契

關於斐波那契數列的定義和應用網上已經有一大堆介紹了,可以去查一查。我以前只知道用循環和遞歸這兩種方式求,但是最近發現一種矩陣乘方的方式來求解。因此就用C語言實現了這3中方式。

  1. 求斐波那契第n個數,循環
  2. 求斐波那契第n個數,遞歸(n大了后會有很多重復運算,不推薦)
  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中方式的優缺點。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM