場景
今天去面試futu, 被問到一題 -> 引數為數字, 輸出斐波那契數列對應結果, 實現了一下
function
fibonacci
(n)
然後面試官問: "你覺得這個有什麼問題 ?"
我: "(⊙o⊙)…忘記判斷引數型別了."
面試官: "不是這個問題."
我: "嗯..嗯...嗯.呃...這個..."
面試官: "如果數字很大會怎麼樣?"
我: "會...效能很差"
面試官: "嗯, 會**, 為什麼? 那怎麼改?"
我: "嗯..嗯...嗯.呃...不會..."
面試官: "你回去查一下吧."
game over
回來查原來 有個概念叫尾呼叫優化, 果然還是太菜
什麼是尾呼叫
尾呼叫的概念非常簡單,一句話就能說清楚,就是指某個函式的最後一步是呼叫另乙個函式。尾呼叫-阮一峰
尾呼叫之所以與其他呼叫不同,就在於它的特殊的呼叫位置。我們知道,函式呼叫會在記憶體形成乙個"呼叫記錄",又稱"呼叫幀"(call frame),儲存呼叫位置和內部變數等資訊。如果在函式a的內部呼叫函式b,那麼在a的呼叫記錄上方,還會形成乙個b的呼叫記錄。等到b執行結束,將結果返回到a,b的呼叫記錄才會消失。如果函式b內部還呼叫函式c,那就還有乙個c的呼叫記錄棧,以此類推。所有的呼叫記錄,就形成乙個"呼叫棧"(call stack)。
遞迴的計算過程(recursive process)包含了兩個階段,先逐級擴充套件(expansion),構造起乙個由被推遲的操作組成的鏈條(會被直譯器儲存在堆疊裡),然後在收縮(contraction)階段逐級回溯執行那些操作。隨著遞迴計算步驟的增多,這種方法消耗的資源會越來越大,而且會包含越來越多的冗餘操作,上面那個求斐波那契數列的例子(在sicp裡被稱作「樹形遞迴」)在這方面問題尤其嚴重,因為它的計算步驟會隨著引數而指數性的增長。
尾呼叫由於是函式的最後一步操作,所以不需要保留外層函式的呼叫記錄,因為呼叫位置、內部變數等資訊都不會再用到了,只要直接用內層函式的呼叫記錄,取代外層函式的呼叫記錄就可以了。優化->尾呼叫
function
lastfibonacci
(n, acc1, acc2)
lastfibonacci(6
,1,1
)//8
lastfibonacci(7
,1,1
)//13
這樣每次都要輸入1,1,可以用柯里化或es6
加柯里化或es6
// 再封裝一層柯里化-----------
function
curringf
(acc1, acc2)
}let func =
curringf(1
,1)func(6
)// 8
func(7
)// 13
//或 es6---------
function
lastfibonacci
(n, acc1=
1, acc2=1)
lastfibonacci(7
)//13
啊啊啊啊啊啊啊啊啊啊啊 尾呼叫優化
尾呼叫 tail call 是函式式程式設計的乙個重要概念,本文介紹它的含義和用法。一 什麼是尾呼叫?尾呼叫的概念非常簡單,一句話就能說清楚,就是指某個函式的最後一步是呼叫另乙個函式。function f x 上面 中,函式f的最後一步是呼叫函式g,這就叫尾呼叫。以下兩種情況,都不屬於尾呼叫。情況一...
尾呼叫優化
本文 日期 2015年4月10日 尾呼叫 tail call 是函式式程式設計的乙個重要概念,本文介紹它的含義和用法。尾呼叫的概念非常簡單,一句話就能說清楚,就是指某個函式的最後一步是呼叫另乙個函式。function f x 上面 中,函式f的最後一步是呼叫函式g,這就叫尾呼叫。以下兩種情況,都不屬...
尾呼叫優化
尾呼叫的概念非常簡單,一句話就能說清楚,就是指某個函式的最後一步是呼叫另乙個函式。function f x 上面 中,函式f的最後一步是呼叫函式g,這就叫尾呼叫。以下兩種情況,都不屬於尾呼叫。情況一 function f x 情況二 function f x 上面 中,情況一是呼叫函式g之後,還有別...