今天在看設計模式時提到了尾遞歸優化,于是去網上搜索了一下,又重新讓我認識了遞歸的另一種方式,由此記錄下來.
-
之前寫過一些算法題,相信大部分人在做算法題時都會避開用遞歸,為什么呢,因為遞歸的調用會讓上一層的方法信息,和一些參數都保存在堆棧中,于是乎如果層數太多,堆棧就會溢出,拋出
StackOverflowError
這個異常,因為java虛擬機在運行方法時會給每個方法分配一個堆棧空間,方法過多,剩余空間不夠了就會拋那個異常;但是尾遞歸就不太可能會有這個問題,先看一下代碼拿斐波那契數列舉例,普通的遞歸會這么寫:
public static long recu(int n){ if (n < 2){ return n; }else { return recu(n-1)+recu(n-2); } }
可以看出方法內部的return會不斷保留上一層方法的信息
再看一下尾遞歸:
public static long tailRe(int n, long a, long b){ if (n == 0){ return a; }else { return tailRe(n-1, b,a+b); } }
尾遞歸在返回時不會積累上層方法的信息,因為在調用下一層方法時上層方法已經不起作用了,所以可以直接把上層方法去除掉,節省堆棧空間
比較一下結果:
尾遞歸
- 仔細思考一下,發現尾遞歸的方式就是要滿足在方法返回語句內遞歸方法是返回語句的末尾,且不能有式子出現,因為這樣的話最上層方法需要取得下層方法的結果再來執行本方法,就會產生堆棧空間的大量占用.