最近刷leetcode 79題 Word Search須要用到DFS算法,因爲是刷leetcode,心想不能用遞歸,影響效率,因而利用stack完成。以後又利用遞歸(使用cache)實現了一次,結果居然是遞歸的算法比非遞歸更快。算法
對於遞歸,一般會有效率低下的映像,通常是由於2點:編程
對於重複計算,能夠緩存計算結果來解決。數組
對於函數調用開銷,能夠利用「尾遞歸」來解決,不過目前的v8引擎並無實現對尾遞歸的優化,因此最開始我覺得遞歸沒有理由比非遞歸更快。緩存
非遞歸的DFS算法使用一個「堆棧」來實現。而一樣,函數調用也是利用「棧」來完成。數據結構
首先,Javascipt並無原生的堆棧這個數據結構,一般是利用數組來實現,效率上應該會有所損失。函數式編程
其次,系統堆棧快於手動堆棧是沒有疑問的,並且系統堆棧使用的是寄存器,比內存要快不少。函數
最後,函數調用會有額外開銷這個是無法避免的,可是當函數變量很少,遞歸層級不深的時候,這個開銷帶來的效率損失不能抵消系統堆棧帶來的效率提高。優化
綜合來看,在不爆棧的狀況下,大部分Javascript代碼裏使用了緩存的遞歸在算法效率上高於非遞歸算法,而且遞歸算法的表現力是徹底高於非遞歸的。不少時候,出於臆斷進行的所謂優化,徹底是負優化。code
以前在看SICP的時候,發現函數式編程沒有循環,非函數式語言的循環操做都是利用「遞歸」的形式來完成的。並且全部的遞歸,均可以改爲迭代的形式,避免了遞歸重複計算的缺點,也無需使用緩存來加速遞歸的計算,省下了緩存的開銷,因此有句話叫作「全部循環都是尾遞歸」。遞歸