具有memoization的尾递归pow()算法?

时间:2010-04-04 17:26:57

标签: algorithm tail-recursion memoization exponentiation

我正在寻找一种算法来计算尾部递归的pow(),并使用memoization来加速重复计算。

表现不是问题;这主要是一项智力练习 - 我花了一个火车来实现我能做的所有不同的pow()实施,但却无法想出一个我满意的具有这两个属性的实现。

我最好的镜头如下:

def calc_tailrec_mem(base, exp, cache_line={}, acc=1, ctr=0):
    if exp == 0:
        return 1
    elif exp == 1:
        return acc * base
    elif exp in cache_line:
        val = acc * cache_line[exp]
        cache_line[exp + ctr] = val
        return val
    else:
        cache_line[ctr] = acc        
    return calc_tailrec_mem(base, exp-1, cache_line, acc * base, ctr + 1)

它有效,但它不会记住所有计算的结果 - 只有那些带有指数1..exp/2exp的计算结果。

3 个答案:

答案 0 :(得分:2)

如果使用SICP section 1.2.4 Exponentiation中描述的连续平方技术,您将获得更好的性能。它不使用memoization,但一般方法是O(log n)而不是O(n),所以你仍然应该看到改进。

我从练习1.16 here谈论迭代过程的解决方案。

答案 1 :(得分:0)

我不认为你在缓存中记录正确的东西,当你用不同的参数调用它时映射会改变。

我认为您需要缓存(base,exp) - > POW(碱,EXP)。

我理解ctr的用途,以及为什么只记录了你期望的一半。

考虑calc_tailrec_mem(2,4):第一级,pow(2,1)记录为2,下一级= calc_tailrec_mem(2,3,...),并记录pow(2,2)。下一级是calc_tailrec_mem(2,2,...),但是已经保存在缓存中,因此递归停止。

这个函数非常令人困惑,因为它的缓存与它应该计算的东西完全不同,这是由于acculumator和ctr

答案 2 :(得分:0)

这太晚了,但是那里的任何人都在寻找答案,这里是:

int powMem(int base,int exp){
    //initializes once and for all
    static map<int,int> memo;

    //base case to stop the recursion
    if(exp <= 1) return base;

    //check if the value is already calculated before. If yes just return it.
    if(memo.find(exp) != memo.end())
        return memo[exp];

    //else just find it and then store it in memo for further use.
    int x = powMem(base,exp/2);
    memo[exp] = x*x;

    //return the answer
    return memo[exp];
}

这使用备忘录数组 - 确切地说是一个地图 - 来存储已计算的值。