【问题标题】:C++ Memoization understandingC++ 记忆化理解
【发布时间】:2012-09-27 01:35:01
【问题描述】:

我试图了解记忆化在 C++ 中的工作原理,因此我查看了 Fib 中使用的记忆化示例。顺序。

std::map<int, int> fibHash;

int memoized_fib (int n)
{
    std::map<int, int>::iterator fibIter = fibHash.find(n);
    if( fibIter != fibHash.end() ) return *fibIter;

    int fib_val;
    if( n <=1 )    fib_val = 1;
    else           fib_val = memoized_fib ( n-1 ) + memoized_fib ( n-2 );

    fibHash[ n ] = fib_val;
    return fib_val;
}

我对 fibHash[n] 的工作原理有点困惑。它是否只保存每个 fib(#) 的单个值?此外,迭代器遍历索引以在表中查找正确的值并返回?例如 fib(6) = 找到 fib(5) 和 fib(4),已经存储并添加它们?

【问题讨论】:

    标签: c++ arrays recursion map memoization


    【解决方案1】:

    它是否只保存每个 fib(#) 的单独值?

    是的。

    另外,迭代器遍历索引以在表中查找正确的值并返回?

    是的。

    例如 fib(6) = 找到 fib(5) 和 fib(4),已经存储并添加它们?

    视情况而定。首先 fib(6) 搜索以查看之前是否调用过 fib(6)。如果有,则返回存储的答案。如果它从未被调用过,则调用 fib(5) 和 fib(4)。有趣的是,如果必须计算 fib(5),它会在 fib(6) 之前调用 fib(4)*,然后当 fib(6) 也调用 fib(4) 时,可以保证在 fibHash 中找到结果,因为fib(5) 已经调用了 fib(4)。这就是导致 fib(n) 从指数时间坍缩成更像线性的东西的原因。

    斐波那契的朴素递归实现归结为多次加 1。

    fib(5) =
    fib(4)                                     + fib(3) =
    fib(3)                   + fib(2)          + fib(2)          + fib(1) =
    fib(2)          + fib(1) + fib(1) + fib(0) + fib(1) + fib(0) + fib(1) =
    fib(1) + fib(0) + fib(1) + fib(1) + fib(0) + fib(1) + fib(0) + fib(1) = 
    1      + 1      + 1      + 1      + 1      + 1      + 1      + 1 =
    8
    

    实际上,要计算 fib(n),您最终需要进行 fib(n)-1 加法。但是,如果在计算 fib(n) 的过程中您保存并使用之前计算的斐波那契数,那么您不再需要执行这么多的加法。以这种方式计算 fib(n) 只需要 n 次加法:

    fib(5) =
    fib(4)                            + fib(3) =
    fib(3)                   + fib(2) + fib(3) =
    fib(2)          + fib(1) + fib(2) + fib(3) =
    fib(1) + fib(0) + fib(1) + fib(2) + fib(3) = 
    1      + 1      + 1      + 2      + 3 =
    8
    

    * 虽然不能保证顺序。 fib(6) 可以先调用 fib(4),然后当 fib(6) 调用 fib(5) 时,fib(5) 调用 fib(4) 现在保证返回一个存储的值。

    【讨论】:

      【解决方案2】:

      代码确实将每个fib_val 保存到fibHash 映射中。在fibHash 上调用的find 方法会搜索地图以查看之前是否计算过该值。如果是这样,find 在这个值上返回一个迭代器,函数返回它 (return *fibIter)。

      fibHash[ n ] = fib_val; 在地图中添加一个新值。

      【讨论】:

      • 感谢您的清理,那么变量 fibHash 是如何工作的?它只是一个数组吗?我可以只使用向量 来存储值吗?
      • 您可能想了解map 的工作原理。它将 keyvalue 相关联。在这种情况下,您不能使用向量,因为您需要将一个数字 映射 到他的 fib 值。在您的代码中,key 是数字,valuememoized_fib 调用此数字的结果。
      【解决方案3】:

      你说的基本正确。

      “它 [fibHash] 是否只保存每个 fib(#) 的单独值?”

      是的,没错。这些值在计算时被填充(使用fibHash[ n ] = fib_val;)。较低的 fib 值用于计算较高的值。

      fibHash 映射将 X 映射到 fib(X),简单明了。

      这样做的好处是,如果你计算 fib(20),然后计算 fib(21) 和 fib(23),然后可能是 fib(15),你只需要计算一次中间值。

      这种加速的成本是在fibHash 中存储值的内存。

      【讨论】:

        猜你喜欢
        • 2016-10-14
        • 2015-05-13
        • 1970-01-01
        • 1970-01-01
        • 2011-07-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-27
        相关资源
        最近更新 更多