我正在尝试使用memoization来优化Fibonacci函数的显式自递归实现。以下是相当标准的实现(虽然关注实际问题,但这是一个简单且相当天真的实现)。
Function.prototype.memoize = function () {
var originalFunction = this,
slice = Array.prototype.slice;
cache = {};
return function () {
var key = slice.call(arguments);
if (key in cache) {
return cache[key];
} else {
return cache[key] = originalFunction.apply(this, key);
}
};
};
现在,在创建和记忆函数时,如下所示,这适用于 1 。 (情景1)
var fibonacci = function (n) {
return n === 0 || n === 1 ? n : fibonacci(n - 1) + fibonacci(n - 2);
}.memoize();
console.log(fibonacci(100));
但是,以下情况并非如此。 2 (情景2)
var fibonacci = function (n) {
return n === 0 || n === 1 ? n : fibonacci(n - 1) + fibonacci(n - 2);
};
console.log(fibonacci.memoize()(100));
这两者都没有。 2 (情景3)
function fibonacci(n) {
return n === 0 || n === 1 ? n : fibonacci(n - 1) + fibonacci(n - 2);
}
console.log(fibonacci.memoize()(100));
我的假设是,由于在函数上调用memoize()
的方式不同,因此正在发生变化。请注意,功能在其他方面是相同的。我想这可能是因为除了第一个例子之外,只有第一个调用被记忆,而不是递归调用。
问题
如果我的上述假设确实正确,那为什么会发生这种情况?有人可以详细解释后两种情况与第一种不同的情况吗?
1 在这个实例中工作意味着返回第100个Fibonacci数,因为只有在使用memoization时才可以递归计算它。
2 不工作就是让浏览器崩溃。
答案 0 :(得分:1)
是的,在第二和第三种情况下只记住第一个电话是正确的。
在第一个场景中,对原始函数的引用仅作为值存在,然后memoize
应用于该值,fibonacci
变量包含对memoized函数的引用。
在第二和第三种情况中,fibonacci
是对原始函数的引用。包含对memoized函数的引用的表达式fibonaci.memoize()
的值仅在调用一次之前作为值存在。
memoize
方法不会更改原始函数,而是返回包装原始函数的新函数。原始函数没有改变,要使用memoization,你必须调用memoize
方法返回的函数。
在函数对fibonacci
进行递归调用的第一个场景中,它是使用的memoized函数。在进行递归调用的第二个和第三个场景中,fibonacci
是原始函数。