记忆化的递归阶乘函数
Memoized, recursive factorial function?
我知道如何在Python中轻松地进行内存化,但我需要一种更快的方法来计算它们,所以我使用C++。然而,我不知道如何记忆。我知道这是关于将值存储到数组或向量中,然后在检索时扫描其值,但了解如何做到这一点会非常有帮助,这样我就可以尝试它的速度。
只是为了好玩,这里有一个我前段时间写的通用备忘录。它需要可变的模板,自然:
template <template <typename...> class Container, typename...> struct Memo;
template <typename R, typename... Args, template <typename...> class Container>
struct Memo<Container, R, std::tuple<Args...>>
{
Memo(std::function<R(Args...)> f) : func(f) { }
R operator()(Args && ...args)
{
const auto arg = std::make_tuple(args...);
typename CacheContainer::const_iterator it = cache.find(arg);
if (it == cache.cend())
{
it = cache.insert(typename CacheContainer::value_type(arg, func(std::forward<Args>(args)...))).first;
std::cout << "New call, memoizing..." << std::endl;
}
else
{
std::cout << "Found it in the cache!" << std::endl;
}
return it->second;
}
private:
typedef Container<typename std::tuple<Args...>, R> CacheContainer;
std::function<R(Args...)> func;
CacheContainer cache;
};
template <typename R, typename... Args>
Memo<std::map, R, std::tuple<Args...>> OMapMemoize(R(&f)(Args...))
{
return Memo<std::map, R, std::tuple<Args...>>(f);
}
template <typename R, typename... Args>
Memo<std::unordered_map, R, std::tuple<Args...>> UMapMemoize(R(&f)(Args...))
{
return Memo<std::unordered_map, R, std::tuple<Args...>>(f);
}
我不完全确定我是否正确地表达了右倾,因为我写这篇文章是很久以前的事了。无论如何,这里有一个测试用例:
int foo(double, char) { return 5; }
int main()
{
auto f = OMapMemoize(foo);
auto g = UMapMemoize(foo);
int a, b;
a = f(1.0, 'a');
a = f(1.0, 'a');
a = f(1.0, 'a');
a = f(1.0, 'a');
b = g(1.0, 'a');
b = g(1.0, 'a');
b = g(1.0, 'a');
b = g(1.0, 'a');
return a;
}
在C++中,我能想到的最简洁的方法可能是使用函数对象来存储存储的值。我想这可能与您的python装饰器有点相似,尽管我从未真正做过任何python。代码看起来像这样:
template <typename T, T (*calc)(T)>
class mem {
std::map<T,T> mem_map;
public:
T operator()(T input) {
typename std::map<T,T>::iterator it;
it = mem_map.find(input);
if (it != mem_map.end()) {
return it->second;
} else {
T output = calc(input);
mem_map[input] = output;
return output;
}
}
};
代码定义了一个模板类,该类接受类型名和函数指针,然后在类上定义函数运算符,从而允许调用它。函数运算符接收输入值,检查所述值是否在映射中,然后简单地从映射中返回或计算(使用函数指针),将其添加到映射,然后返回。
所以假设你定义了一些处理函数,比如:
int unity(int in) { return in; }
你会使用这样的代码:
mem<int, unity> mem_unity;
int y;
y = mem_unity(10);
因此,我们定义了一个mem类的实例,该实例将我们的值类型和处理函数作为模板参数,然后简单地将该类作为函数调用。
除了学习递归的学生,没有人会用这种方式计算阶乘。
Memoization是一个非常好的主意,尤其是如果要重复调用该方法。为什么要放弃好的工作?
另一个考虑因素是计算阶乘的更好方法:使用gamma函数的自然对数。它将在更长时间内防止溢出,因为您返回了一个双值。自然对数的增长速度将比数值慢。如果你在计算组合,自然对数会把乘法和除法变成加法和减法。
但是,无论如何,要记住您使用的任何实现。如果您是用C++编写的,我建议使用参数x
为键、ln(gamma(x))
为值的std:map
。
对不起,我已经很久没有写C++和STL了。我宁愿使用具有O(1)
读取访问时间的哈希映射,而不必迭代O(n)
中的密钥。
我喜欢像在(使用std=c++14
)中那样依赖lambda捕获
template<typename R, typename... Args>
auto memoize(std::function<R(Args...)>&& f)
{
using F = std::function<R(Args...)>;
std::map<std::tuple<Args...>,R> cache;
return ([cache = std::map<std::tuple<Args...>,R>{},
f = std::forward<F>(f)](Args&&... args) mutable
{
std::tuple<Args...> t(args...);
if (cache.find(t) == cache.end())
{
R r = f(std::forward<Args...>(args)...);
cache[t] = r;
}
return cache[t];
});
}
- 在 C++ 中的数组上使用阶乘函数
- 为什么我在C++阶乘函数中出现编译错误?
- 阶乘函数只返回C++中输入的答案
- 为什么我不能在非常量表达式上使用此模板阶乘函数?
- 返回阶乘C++的递归函数
- C++ 中是否有任何内置阶乘函数?
- 为什么叮当使我的简单阶乘函数过于复杂
- 3 函数加主函数 C 程序计算和显示阶乘
- 带有自定义数字的阶乘函数不起作用
- 阶乘函数不适用于大数
- 自定义阶乘函数未按预期工作
- 递归阶乘函数在"22!"上产生不正确的结果
- 为什么这个阶乘函数返回int而不是double
- 在C++中跟踪递归阶乘函数
- 带有值的递归阶乘错误返回语句,在函数中返回 'void' [-fallowive]
- 记忆化的递归阶乘函数
- 了解如何在c++中使用阶乘函数
- 为什么阶乘递归函数比普通阶乘函数效率低
- 有数据类型问题的c++阶乘函数
- 如何在c++中实现阶乘函数并进行正确的错误处理