帶有 memoization 的遞迴
遞迴函式可能會非常昂貴。如果它們是純函式(當使用相同的引數呼叫時總是返回相同的值,並且既不依賴也不修改外部狀態),通過儲存已經計算的值,可以以犧牲記憶體為代價使它們更快。
以下是具有 memoization 的 Fibonacci 序列的實現:
#include <map>
int fibonacci(int n)
{
static std::map<int, int> values;
if (n==0 || n==1)
return n;
std::map<int,int>::iterator iter = values.find(n);
if (iter == values.end())
{
return values[n] = fibonacci(n-1) + fibonacci(n-2);
}
else
{
return iter->second;
}
}
請注意,儘管使用簡單的遞迴公式,但在第一次呼叫時此函式為$ O(n)
$。在具有相同值的後續呼叫中,它當然是$ O(1)
$。
但請注意,此實現不可重入。此外,它不允許擺脫儲存的值。另一種實現方式是允許將地圖作為附加引數傳遞:
#include <map>
int fibonacci(int n, std::map<int, int> values)
{
if (n==0 || n==1)
return n;
std::map<int,int>::iterator iter = values.find(n);
if (iter == values.end())
{
return values[n] = fibonacci(n-1) + fibonacci(n-2);
}
else
{
return iter->second;
}
}
對於此版本,呼叫者需要使用儲存的值維護對映。這樣做的好處是該函式現在可以重入,並且呼叫者可以刪除不再需要的值,從而節省記憶體。它的缺點是它破壞了封裝; 呼叫者可以通過使用不正確的值填充對映來更改輸出。