在計算機(jī)領(lǐng)域诗充,記憶(memoization)是主要用于加速程序計算的一種優(yōu)化技術(shù)惶傻,它使得函數(shù)避免重復(fù)鹽酸之前已被處理的輸入,而返回已緩存的結(jié)果其障。
————摘自維基百科
函數(shù)可以將先前操作的結(jié)果記錄在某個對象里银室,從而避免無謂的重復(fù)運(yùn)算。JavaScript的對象和數(shù)組要實現(xiàn)這種優(yōu)化是非常方便的励翼,本文將實現(xiàn)一個遞歸函數(shù)蜈敢,來計算Fibonacci(斐波那契數(shù)列)。
下列數(shù)組就是一個斐波那契數(shù)列汽抚,(前面相鄰兩項之和等于后一項的值)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
遞歸實現(xiàn)很簡單抓狭,代碼如下:
var fibonacci = function (n) {
console.count('fibonacci被執(zhí)行的次數(shù):')
return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2)
}
document.body.innerHTML = fibonacci(10)
乍一看,一行代碼搞定造烁。但是會有些問題否过,這里用console.count計算了下fibonacci函數(shù)被執(zhí)行的次數(shù),結(jié)果顯示:fibonacci被執(zhí)行的次數(shù): 177
可以看出它做了很多無用功惭蟋,我們只調(diào)用了一次fibonacci函數(shù)苗桂,它自己卻調(diào)用了自己176次。
我們可以利用閉包告组,使我們的函數(shù)具備記憶功能煤伟。在函數(shù)內(nèi)部聲明一個memory數(shù)組來儲存結(jié)果,每次調(diào)用時木缝,先判斷需要的值是否存在便锨,如果存在直接取就好了。
var fibonacci = function (n) {
var memory = [0, 1];
(function run(n) {
console.count('run執(zhí)行次數(shù)')
var result = memory[n]
if (typeof memory[n] !== 'number') {
result = run(n - 1) + run(n - 2)
memory[n] = result
console.count('計算次數(shù)')
}
return result
})(n)
return memory[n]
}
document.body.innerHTML = fibonacci(10)
run執(zhí)行次數(shù): 19
計算次數(shù): 9
控制臺結(jié)果顯示我碟,計算次數(shù)顯示只有9次放案!其余都是直接拿緩存的結(jié)果。我們可以多打印些日志矫俺,看下函數(shù)的入棧出棧順序吱殉,加深理解。
var fibonacci = function (n) {
var memory = [0, 1];
(function run(n) {
console.group('run') // 用group分組查看打印日志恳守,很給力~
console.log('memory[%d]: ', n, memory[n])
var result = memory[n]
if (typeof memory[n] !== 'number') {
result = run(n - 1) + run(n - 2)
memory[n] = result
console.log(`%c計算結(jié)果 ${result}`, 'color: red;')
console.count('計算次數(shù)')
} else {
console.log('直接拿到結(jié)果', result)
}
console.log('memory', memory)
console.groupEnd()
return result
})(n)
return memory[n]
}
打印結(jié)果: