斐波那契数
- 1,1,2,3,5,8,13,21….从第3个数开始,每个数等于它前面的两个数之和。
- 斐波那契公式为:
{F(0)=F(1)=0F(n)=F(n−1)+F(n−2) n≥3 { F ( 0 ) = F ( 1 ) = 0 F ( n ) = F ( n − 1 ) + F ( n − 2 ) n ≥ 3
递归算法
- 从公式中能看出,可以采用递归的算法算第n个斐波那契数的值。
- 递归基准条件(终止条件)为 n==0或1。
int Fabonacci(int n)
{
if (n <= 1)
return 1;
else
return Fabonacci(n - 1) + Fabonacci(n - 2);
}
算法评价
- 斐波那契数递归算法是递归应用的一个不好的例子。
- 原因在于,每次计算都要执行两次递归,而且两次递归产生了大量的重复计算。
- 例如要计算F(4):那么要计算出F(3)和F(2),F(3)通过F(2)和F(1)计算返回,F(3)的F(2)通过F(1)和F(0)计算返回,F(4)的F(2)通过F(1)和F(0)计算返回。整个过程F(0)计算2次、F(1)计算3次、F(2)计算2次、F(3)和F(4)分别计算1次。
- 大量重复的计算,使得复杂度呈指数爆炸增长。
动态规划的算法
- 动态规划的算法把原问题分成一个个子问题,记录子问题的解来求原问题的解。
例如:
F(n)=F(n−1)+F(n−2) n≥3 F ( n ) = F ( n − 1 ) + F ( n − 2 ) n ≥ 3
每次记录子问题F(n-1)和F(n-2),下次就能直接拿来计算F(n)。
- 动态规划也有基准即子问题的边界,这里和递归一样F(0)=F(1)=0。
int FabonacciD(int n)
{
int Fa = 1; // 初始化Fa=1,Fa为要求第n个数值的前两位数即n-2个数值
int Fb = 1; // 初始化Fb=1,Fb为要求第n个数值的前一位数即n-1个数值
int Fab = 0;
for (int i = 2;i <= n;i++)
{
Fab = Fa + Fb; // Fab 每次由位于它之前的两个斐波那契数相加
Fa = Fb; // 更新Fa数值为原来的Fb
Fb = Fab; // 更新Fb数值为原来的Fab
}
return Fab;
}
算法评价
- 每个F(n)只需计算一次然后记录下来,避免了大量重复的计算。
- 动态规划通过牺牲空间复杂度来换取时间复杂度的降低。单大多情况下牺牲是值得的。
附斐波那契数两种计算方式及运行时间比较C++
#include<iostream>
#include<ctime>
using namespace std;
int Fabonacci(int n)
{
if (n <= 1)
return 1;
else
return Fabonacci(n - 1) + Fabonacci(n - 2);
}
int FabonacciD(int n)
{
int Fa = 1; // 初始化Fa=1,Fa为要求第n个数值的前两位数即n-2个数值
int Fb = 1; // 初始化Fb=1,Fb为要求第n个数值的前一位数即n-1个数值
int Fab = 0;
for (int i = 2;i <= n;i++)
{
Fab = Fa + Fb; // Fab 每次由位于它之前的两个斐波那契数相加
Fa = Fb; // 更新Fa数值为原来的Fb
Fb = Fab; // 更新Fb数值为原来的Fab
}
return Fab;
}
int main()
{
int n = 40;
clock_t start, finish;
cout << "NO." << n << "'s Fabonacci number in a recursion way:\n";
start = clock();
cout << Fabonacci(n) << endl;
finish = clock();
cout << "Cost Time: ";
cout << static_cast<double>(finish - start) / CLOCKS_PER_SEC * 1000 << "ms" << endl;
cout << "NO." << n << "'s Fabonacci number in a Dynamic programming way:\n";
start = clock();
cout << FabonacciD(n) << endl;
finish = clock();
cout << "Cost Time: ";
cout << static_cast<double>(finish - start) / CLOCKS_PER_SEC * 1000 << "ms" << endl;
system("pause");
return 0;
}
- 运行结果
NO.40's Fabonacci number in a recursion way:
165580141
Cost Time: 3980ms
NO.40's Fabonacci number in a Dynamic programming way:
165580141
Cost Time: 0ms
请按任意键继续. . .
- 从计算第40个斐波那契数可以明显看出,采用动态规划的方式计算速度远远快于采用递归的方式计算。