问题描述
我正在尝试使用记忆化在 C++ 中实现斐波那契函数。我的实现有效,但速度非常慢。 为什么我的实现这么慢?我在 javascript 中看到过类似的实现,使用对象进行记忆,它们非常快。 是因为我使用了地图数据结构吗?
#include <iostream>
#include <map>
unsigned int fib(unsigned short n,std::map<unsigned short,unsigned int> memo = {});
int main(void)
{
for (unsigned short i = 0; i <= 50; i++)
{
std::cout << i << " " << fib(i) << std::endl;
}
};
unsigned int fib(unsigned short n,unsigned int> memo)
{
if (memo.find(n) != memo.end())
{
return memo.find(n)->second;
}
if (n <= 2)
{
return 1;
}
memo.insert(
std::pair<unsigned short,unsigned int>(
n,fib(n - 1,memo) + fib(n - 2,memo)));
return memo.find(n)->second;
}
解决方法
,std::map<unsigned short,unsigned int> memo)
那是地图的副本。
您每次通话都在复制您的备忘地图,然后忘记添加到其中的任何内容。
unsigned int fib(unsigned short n,unsigned int>* memo = nullptr);
unsigned int fib(unsigned short n,unsigned int>* pmemo)
{
std::map<unsigned short,unsigned int> local;
auto& memo = pmemo?*pmemo:local;
然后将 &memo
传递给 fib
的递归调用。
这会在每次递归调用时占用一点额外的堆栈空间,但仅当您进行 100,000 多次调用时才值得担心。
unsigned int fib(unsigned short n)
{
std::map<unsigned short,unsigned int> memo = {
{0u,0u},{1u,1u},{2u,};
std::vector<unsigned short> todo = {n};
while (!todo.empty()) {
// solved?
if (memo.find(todo.back()) != memo.end())
{
todo.pop_back();
continue;
}
unsigned short a = todo.back()-1;
unsigned short b = todo.back()-2;
auto ita = memo.find(a);
auto itb = memo.find(b);
// solved?
if (ita != memo.end() && itb != memo.end())
{
memo.insert( {todo.back(),ita->second+itb->second} );
todo.pop_back();
continue;
}
todo.push_back(a);
todo.push_back(b); // could skip this actually
}
return memo.find(n)->second;
}
这是一个手动维护待办事项的“调用堆栈”而不是使用递归调用的示例。