现在说一下递归求解斐波那契数,直接模拟递推公式
递推公式
Fn=F(n-1)+F(n-2)(n>=2,n∈N*)
long long func(int n) {
if (n == 1 || n == 2) {
return 1;
}
return func(n - 1) + func(n - 2);
}
但是说一下使用递归求解的最常见问题:1、出现冗余程序分支 2、对于较大数据的计算会使用较多的堆栈内存 3、同样是处理较大数据时,可能会爆栈。
先说冗余分支,画了个图:
意思就是计算第五个斐波那契数需要先计算第3和第4个斐波那契数,但是计算第4个的时候又要计算第3个。但是由于处于不同的递归深度,递归函数不知道自己算过了,那么就出现了重复运算。而且恐怖的是:这种重复计算应该是一个指数增长的。
接下来说一下最常用的程序分支优化方法:
long long func_1(int n) {
if (n == 1 || n == 2) {
record[n] = 1;
return record[n];
}
if (record[n])
return record[n];
else {
record[n] = func_1(n - 1) + func_1(n - 2);
return record[n];
}
}
用一个额外的数组来存储已经计算过的值。
接下来我进行了一个测试,用运行时间来说明优化效果
#include <iostream>
#include <vector>
#include <cstring>
#include <string>
#include <map>
#include <math.h>
#include <algorithm>
#include <stdio.h>
#include <windows.h>
using namespace std;
vector<long long> record;
long long func(int n) {
if (n == 1 || n == 2) {
return 1;
}
return func(n - 1) + func(n - 2);
}
long long func_1(int n) {
if (n == 1 || n == 2) {
record[n] = 1;
return record[n];
}
if (record[n])
return record[n];
else {
record[n] = func_1(n - 1) + func_1(n - 2);
return record[n];
}
}
long long func_2(int n) {
if (n == 1 || n == 2) {
return 1;
}
long long pre_1, pre_2,current;
pre_1 = 1;
pre_2 = 1;
for (int i = 3; i <= n;i++) {
current = pre_1 + pre_2;
pre_1 = pre_2;
pre_2 = current;
}
return current;
}
int main() {
int N=0;
cout << "求第N位斐波那契数:N=";
cin >> N;
cout << endl;
record.assign(N+1,0);
DWORD start;
start = GetTickCount();
cout << func_2(N) << endl;
cout << "迭代用时:" << (GetTickCount() - start) << endl;
//start = GetTickCount();
//cout<<func(N)<<endl;
//cout << "直接递归的用时:" <<(GetTickCount() - start) << endl;
start = GetTickCount();
cout << func_1(N) << endl;
cout << "优化重复运算的用时:"<<(GetTickCount() - start) << endl;
system("pause");
return 0;
}
测试结果:
虽然多计算了十个数,但是对于没有优化的递归,用时猛增。我在上面贴的代码中还实现了一下,使用常规的迭代方法,为了对比出递归方法的另外两个缺陷:
当我要求第5000位的时候,迭代方法还是使用了毫秒级的运算就得到了结果(其实long long型已经溢出,但是具体是什么数已经不是我关心的内容),但是递归直接把我的程序栈给用爆了,请看报的异常为“stack overflow”。
我把这篇,归为数学是有原因的,为什么很多搞计算机的人以前是搞数学的?请看:
求斐波那契数就尼玛一行程序,有解析解,根本不用模拟迭代过程。百度上还给我整什么方法二。。。方法还不止一个啊?凑!