C++ - 为什么使用地图的斐波那契记忆化实现如此缓慢?
C++ - Why is this implementation of fibonacci memoization using map so slow?
我正在尝试使用记忆在 C++ 中实现斐波那契函数。我的实施工作但非常慢。 为什么我的实现这么慢? 我在 javascript 中看到过类似的实现,使用对象进行记忆,而且速度非常快。 是不是因为我用了map数据结构?
#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, std::map<unsigned short, 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, std::map<unsigned short, unsigned int>* memo = nullptr);
unsigned int fib(unsigned short n, std::map<unsigned short, unsigned int>* pmemo)
{
std::map<unsigned short, unsigned int> local;
auto& memo = pmemo?*pmemo:local;
然后将&memo
传递给fib
的递归调用。
这会在每次递归调用时占用一些额外的堆栈 space,但只有在进行 100,000 次以上调用时才值得担心。
unsigned int fib(unsigned short n)
{
std::map<unsigned short, unsigned int> memo = {
{0u,0u},
{1u,1u},
{2u,1u},
};
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;
}
这是一个手动维护待办事项“调用堆栈”而不是使用递归调用的示例。
我正在尝试使用记忆在 C++ 中实现斐波那契函数。我的实施工作但非常慢。 为什么我的实现这么慢? 我在 javascript 中看到过类似的实现,使用对象进行记忆,而且速度非常快。 是不是因为我用了map数据结构?
#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, std::map<unsigned short, 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, std::map<unsigned short, unsigned int>* memo = nullptr);
unsigned int fib(unsigned short n, std::map<unsigned short, unsigned int>* pmemo)
{
std::map<unsigned short, unsigned int> local;
auto& memo = pmemo?*pmemo:local;
然后将&memo
传递给fib
的递归调用。
这会在每次递归调用时占用一些额外的堆栈 space,但只有在进行 100,000 次以上调用时才值得担心。
unsigned int fib(unsigned short n)
{
std::map<unsigned short, unsigned int> memo = {
{0u,0u},
{1u,1u},
{2u,1u},
};
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;
}
这是一个手动维护待办事项“调用堆栈”而不是使用递归调用的示例。