Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
记忆化的递归阶乘函数? 我知道如何轻松地在Python中进行记忆,但我需要一种更快的方法来计算它们,所以我使用C++。然而,我不知道如何记忆。我知道这是关于将值存储到数组或向量中,然后在检索时扫描它的值,但如果能看看这是如何做到的,我会很有帮助,这样我就可以试试它的速度了。_C++_Algorithm_Math_Factorial - Fatal编程技术网

记忆化的递归阶乘函数? 我知道如何轻松地在Python中进行记忆,但我需要一种更快的方法来计算它们,所以我使用C++。然而,我不知道如何记忆。我知道这是关于将值存储到数组或向量中,然后在检索时扫描它的值,但如果能看看这是如何做到的,我会很有帮助,这样我就可以试试它的速度了。

记忆化的递归阶乘函数? 我知道如何轻松地在Python中进行记忆,但我需要一种更快的方法来计算它们,所以我使用C++。然而,我不知道如何记忆。我知道这是关于将值存储到数组或向量中,然后在检索时扫描它的值,但如果能看看这是如何做到的,我会很有帮助,这样我就可以试试它的速度了。,c++,algorithm,math,factorial,C++,Algorithm,Math,Factorial,除了学习递归的学生外,没有人会这样计算阶乘 memonization是一个非常好的主意,尤其是当您要重复调用该方法时。为什么要丢掉好工作 另一个考虑因素是计算阶乘的更好方法:使用gamma函数的自然对数。因为返回一个双精度值,所以它可以抵抗更长时间的溢出。自然原木的增长速度将比价值增长慢。如果你在计算组合,自然对数会把乘法和除法变成加法和减法 但是,无论如何,对于您使用的任何实现,都要记住。如果你用C++编写,我建议使用 STD:MAP,以参数 x>代码>为关键字, Ln(伽玛(x))< /C>

除了学习递归的学生外,没有人会这样计算阶乘

memonization是一个非常好的主意,尤其是当您要重复调用该方法时。为什么要丢掉好工作

另一个考虑因素是计算阶乘的更好方法:使用gamma函数的自然对数。因为返回一个双精度值,所以它可以抵抗更长时间的溢出。自然原木的增长速度将比价值增长慢。如果你在计算组合,自然对数会把乘法和除法变成加法和减法

但是,无论如何,对于您使用的任何实现,都要记住。如果你用C++编写,我建议使用<代码> STD:MAP<代码>,以参数<代码> x>代码>为关键字,<代码> Ln(伽玛(x))< /C>作为值。
对不起,我写C++和STL已经太久了。我宁愿使用一个哈希图,而不是代码> o(1)读取访问时间,必须在 o(n)中迭代关键字。

嗯,我想在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;
    }
  }
};
mem<int, unity> mem_unity;
int y;
y = mem_unity(10);
您将使用如下代码:

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;
    }
  }
};
mem<int, unity> mem_unity;
int y;
y = mem_unity(10);
memmem\u统一;
int-y;
y=成员单位(10);

因此,我们定义了一个mem类的实例,它将值类型和处理函数作为模板参数,然后简单地将该类作为函数调用。

为了好玩,这里有一个我不久前编写的通用记忆器。当然,它需要可变模板:

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);
}

我喜欢像中一样依赖lambda捕获(使用
std=c++14

模板
自动记忆(std::function&&f)
{
使用F=std::函数;
地图缓存;
返回([cache=std::map{},
f=std::forward(f)](参数和参数)可变
{
std::元组t(args…);
if(cache.find(t)=cache.end())
{
R=f(标准:正向(参数)…);
cache[t]=r;
}
返回缓存[t];
});
}

我没有投反对票。但我很确定答案是否定的。与递归斐波那契算法不同,对阶乘算法进行记忆没有任何好处。@Mystical:我不同意。斐波那契序列可以用
O(n)
算法编写,就像计算阶乘一样。与记忆的折衷是占用
O(n)
内存进行
O(1)
查找。进行
n
乘法或加法(其中n相对较小)很快。但是如果你反复调用它,记忆化会有帮助。@MikeBantegui Fibonacci可以在
O(pow)
中计算,其中
pow
power()函数的复杂性。这里有一个封闭的公式,我是用decorator语法来做的,所以我不知道如何翻译它。这里有一个不错的问题隐藏在一个写得不好的问题中。记忆化是一种在某些语言中几乎不可见地实现起来很简单的技术,而在其他语言中则需要更多的工作。我不知道如何用C++最方便和通用的方式来完成它,这是没有用的。对
calc()
的第一次调用调用原始的、未迁移的
calc
,如果它是递归的,缓存将不再被查找;但是OP希望通过记忆来加速递归函数。这对于递归函数来说是非常必要的,例如,对于大n,或者在动态规划解决方案中,
factorial(n)
。r值是可以的,至少对于我试过你的记忆工具的东西是可以的@达里奥:谢谢你的检查!这样做的问题是,内部调用不会通过记忆器进行。
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];
    });
}