1. 程式人生 > >尾遞歸和JAVA

尾遞歸和JAVA

pre div 最後一行 pan span logs 兩個 至少 普通

簡單來說,遞歸即是調用自己本身。所有遞歸都應該有至少一個基本條件,在滿足基本條件時不進行遞歸。

給出一個遞歸實例:

1 int fact(int N){
2     if(N==1)
3         return 1;
4     else
5         return N*fact(N-1);
6 }        

每一個遞歸方法的執行都分為前進和回退兩個階段,上例中計算5的階乘,前進階段得到的結果是:

(5*(4*(3*(2*(1)))))

回退階段則由內向外,依次計算括號中的值。

應用到程序中,分別對應壓棧和出棧。考慮到這種做法,每次調用都會壓棧出棧,效率很低。除此之外,每次遞歸創建新的棧在遞歸深度過深的時候,會引起棧溢出,也就是可以分給創建棧的內存不足的情況。尾遞歸的方法由此提出。

尾遞歸,簡單來說,就是將遞歸語句寫到最後一行且不參與任何計算。將上例改寫為尾遞歸為:

 1 int fact(int N){
 2     if(N==1)
 3         return 1;
 4     else
 5         return fact(N-1,N);
 6 }       
 7 
 8 int fact(int N, int M){
 9     if(N==1)
10         return M;
11     else
12         return fact(N-1, N*M);
13 }    

但這要求編譯器能對尾遞歸進行優化,每次重用或者說覆蓋原來遞歸方法的棧,而不是新建棧。遺憾的是JAVA和python都不支持尾遞歸的優化,JAVA的尾遞歸代碼與普通遞歸無異。可能JVM是想在出現異常時更好地輸出堆棧信息的緣故。所以,JAVA中一般能用叠代就不用遞歸。

尾遞歸和JAVA