我正在寻找一种算法来计算尾部递归的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/2
和exp
的计算结果。
答案 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];
}
这使用备忘录数组 - 确切地说是一个地图 - 来存储已计算的值。