我正在尝试使用C ++以及boost和C ++ 11规范来学习memoization。但是我遇到了一个问题,我无法绕过头脑。我在这里遵循一个教程:Memoization in C,教程说你可以使用模板和lambda函数来概括递归函数的memoization。本教程还列出了与模板一起使用的递归factorial和fibonacci函数。但是,该指南仅使用斐波那契函数。
我写了一个测试程序,看看这一切是如何工作的,并在同一次运行中同时制作一个memoized fibonacci和factorial函数。事实上,memoization模板使用静态映射来存储缓存的值,并且看起来映射对于memoized函数的每个实例都不是唯一的。这是预期的吗?我该怎么做才能使地图对每个模板实例都是唯一的?在我开始使用C ++ 11功能之前,我曾尝试创建一个模板类,它接受一个boost函数来封装这个过程。静态地图会在模板类中是唯一的吗?
创建记事本函数的主要逻辑
// Template function to create memoized versions of recursive lambda functions
template<typename inType, typename outType>
std::function<outType(inType) > memoize(std::function<outType(inType) > foo) {
return [foo](inType n) {
static std::map<inType, outType> memo;
outType ret;
if (memo.count(n) > 0) {
cout << "Cache Hit" << endl;
ret = memo[n];
return ret;
}
ret = foo(n);
memo[n] = ret;
return ret;
};
}
// Recursive lambda fibonacci function
std::function<int(int) > fibonacci_r = [](int n) {
if (n <= 1) {
return n;
} else {
return fibonacci_r(n - 1) + fibonacci_r(n - 2);
}
};
// Recursive lambda factorial function
std::function<int(int) > factorial_r = [](int n) {
if (n == 0) {
return 1;
} else {
return n * factorial_r(n - 1);
}
};
测试记忆功能的逻辑
int position = 7;
cout << "Fibonacci:" << endl;
cout << "Non Memo Fibonacci" << endl;
cout << position << "-> " << fibonacci_r(position) << endl;
cout << "Memo Fibonacci" << endl;
fibonacci_r = memoize(fibonacci_r);
cout << position << " -> " << fibonacci_r(position) << endl;
cout << endl;
cout << "Non Memo Factorial" << endl;
cout << position << " -> " << factorial_r(position) << endl;
cout << "Memo Factorial" << endl;
factorial_r = memoize(factorial_r);
cout << position << " -> " << factorial_r(position) << endl;
输出
Fibonacci:
Non Memo Fibonacci
7-> 13
Memo Fibonacci
Cache Hit
Cache Hit
Cache Hit
Cache Hit
Cache Hit
7 -> 13
Non Memo Factorial
7 -> 5040
Memo Factorial
Cache Hit
7 -> 13
在输出的尾端,您可以看到Memo factorial具有缓存命中。但是,我认为它不应该只有1个缓存命中。无论哪种方式,7!
都不是13而13 是斐波纳契备忘录lambda下7的缓存值。
答案 0 :(得分:2)
写作时
...似乎地图并不是每个memoized函数实例都是唯一的。这是预期的吗?
您似乎忘记了实例 wrt到static
变量是基于类型,而不是基于参数的值。类型std::function<outType(inType)>
在两种情况下都是相同的。显然,当只有一个实例时,您也只有一个静态map
。
部分解决方案可能是这样的:
template<typename inType, typename outType>
std::function<outType(inType) > memoize(std::function<outType(inType) > foo) {
static int i = 0;
++i;
return [foo](inType n) {
static std::map<int, std::map<inType, outType>> memo;
auto& m = memo[i];
outType ret;
if (m.count(n) > 0) {
cout << "Cache Hit" << endl;
ret = m[n];
return ret;
}
ret = foo(n);
m[n] = ret;
return ret;
};
}
但请注意,现在每个调用都会生成自己独立的map
。如果你这样做:
auto f1 = memoize(factorial_r);
auto f2 = memoize(factorial_r);
然后f1
和f2
将不共享相同的map
。这也意味着如果经常这样做,最终可能会占用大量内存。