fibonacci遞迴演算法的“備忘錄/Memo”優化法
阿新 • • 發佈:2019-01-09
我們先看一個簡單的fibonacci遞迴程式:
耗費時間(單位毫秒):47890#include <iostream> #include <windows.h> using namespace std; int fun(int n) { if(1 == n || 2 == n) { return n; } return fun(n - 1) + fun(n - 2); } int main() { int i = 0; int n = 1000; // 計算1000次 int t1 = GetTickCount(); for(i = 0; i < n; i++) { fun(30); } int t2 = GetTickCount(); cout << t2 - t1 << endl; return 0; }
仔細畫圖分析就可知, 上述遞迴存在重複計算問題, 下面, 我們用備忘錄法來試試:
結果為:0 . 程式快得離譜啊, 我們看看, 哪裡不公平了, 原來, a中已經存放值了, 所以後面每次都是return a[30];了, 所以, 迴圈測試的時候, 失去了一點公平性, 好吧, 我們來改改:#include <iostream> #include <windows.h> using namespace std; int a[50] = {0}; int funWithMemo(int n) { if(1 == n || 2 == n) { a[n] = n; return a[n]; } if(0 != a[n]) { return a[n]; } int x = funWithMemo(n - 1); int y = funWithMemo(n - 2); a[n] = x + y; return a[n]; } int main() { int i = 0; int n = 1000; // 計算1000次 int t1 = GetTickCount(); for(i = 0; i < n; i++) { funWithMemo(30); } int t2 = GetTickCount(); cout << t2 - t1 << endl; return 0; }
結果, 程式還是0, 可見, 確實快。#include <iostream> #include <windows.h> using namespace std; int a[50] = {0}; int funWithMemo(int n) { if(1 == n || 2 == n) { a[n] = n; return a[n]; } if(0 != a[n]) { return a[n]; } int x = funWithMemo(n - 1); int y = funWithMemo(n - 2); a[n] = x + y; return a[n]; } int main() { int i = 0; int n = 1000; // 計算1000次 int t1 = GetTickCount(); for(i = 0; i < n; i++) { memset(a, 0, 50 * sizeof(int)); // 為了公平起見, 在迴圈測試中, 陣列每次清零 funWithMemo(30); } int t2 = GetTickCount(); cout << t2 - t1 << endl; return 0; }
我們加大測試次數, 程式如下:
#include <iostream>
#include <windows.h>
using namespace std;
int a[50] = {0};
int funWithMemo(int n)
{
if(1 == n || 2 == n)
{
a[n] = n;
return a[n];
}
if(0 != a[n])
{
return a[n];
}
int x = funWithMemo(n - 1);
int y = funWithMemo(n - 2);
a[n] = x + y;
return a[n];
}
int main()
{
int i = 0;
int n = 10000; // 加大到1萬次
int t1 = GetTickCount();
for(i = 0; i < n; i++)
{
memset(a, 0, 50 * sizeof(int)); // 為了公平起見, 在迴圈測試中, 陣列每次清零
funWithMemo(30);
}
int t2 = GetTickCount();
cout << t2 - t1 << endl;
return 0;
}
結果為:16. 可見, 程式確實快。 funWithMemo之所以這麼快, 是因為它採用了備忘錄, 避免了重複的不必要的計算。(實際上, 16毫秒還包括了陣列清零的時間)
採用遞迴, 對於程式設計人員來說, 非常方便, 但效率低下, 此時, 再引入備忘錄, 有時效率會有所提升。 其實, 無論是遞迴帶不帶備忘錄, 速度都不如自底向上的動態規劃演算法。
OK, 本文先閒聊到這裡。