尾遞歸優化

1.什么是遞歸?

程序調用自身的編程技巧稱為遞歸( recursion),就好像你做了一個夢,夢里面夢到夢到自己又做了一個夢,夢中夢。下面看一個例子:

public class JavaTest {

    public static int method(int num) {
        if (num > 1)
            return num + method(num - 1);
        else
            return num;
    }

    public static  void main(String[] args){
        int sum =method(100);//從一加到一百的和
        System.out.println(sum);
    }
}

這樣遞歸的話呢,看上去代碼很簡潔,但是遞歸是存在缺點的,就是在遞歸調用的過程當中系統為每一層的返回點、局部量等開辟了棧來存儲,因此遞歸次數過多容易造成棧溢出。舉個栗子,就是打開一扇門,然后又進去了一扇門,等到return的時候,會從里向外一個一個的return,一個一個的出來,所以之前的這些“門”是占要地方的,遞歸層級過深就會造成堆棧溢出。那么怎么解決這個問題呢?答案就是尾遞歸優化。

2.什么是尾遞歸?

如果一個函數中所有遞歸形式的調用都出現在函數的末尾,我們稱這個遞歸函數是尾遞歸的。當遞歸調用是整個函數體中最后執行的語句且它的返回值不屬于表達式的一部分時,這個遞歸調用就是尾遞歸。

public class JavaTest {
    public static int method(int num,int sum) {
        if (num > 1) {
            sum += num;
            return method(num - 1,sum);
        }
        else {
            return sum+1;
        }
    }
    public static int method(int num) {
        return method(num,0);
    }
    public static  void main(String[] args){
        int sum =method(100);
        System.out.println(sum);
    }
}

如上,使用了一個變量sum保存了遞歸調用的結果,并傳到下一次遞歸調用中,這就是尾遞歸。到遞歸的結尾的時候,就可以直接return,不需要一層一層的出來。這樣的話,就不用保存前面那些函數的堆棧,也就不會堆棧溢出了。

3.編譯器的優化

雖然手寫成了尾遞歸的形式,但是編譯成字節碼的時候,優不優化得看編譯器的心情,所以很蛋疼。編譯器如果支持尾遞歸優化,那么就會利用尾遞歸特點來進行優化,在遞歸調用的時候重復使用同一個函數棧幀,效率很高,however,java還沒有實現尾遞歸優化的支持,官方是推薦使用循環,迭代,不使用遞歸。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 以遞歸方式思考 遞歸通過靈巧的函數定義,告訴計算機做什么。在函數式編程中,隨處可見遞歸思想的運用。下面給出幾個遞歸...
    JasonDing閱讀 1,464評論 0 1
  • 什么是尾遞歸 如果一個函數在定義時引用了自身,那么這個函數就是一個遞歸函數。例如我們所熟知的階乘就可以通過遞歸函數...
    Liutos閱讀 814評論 0 1
  • lua程序設計 書中原文 Lua中函數的另一個有趣的特征是可以正確的處理尾調用(proper tail recur...
    人氣小哥閱讀 3,789評論 0 0
  • 原文出處: neo1218 一般遞歸與尾遞歸 一般遞歸 執行: 可以看到, 一般遞歸, 每一級遞歸都需要調用函數,...
    PyChina閱讀 2,001評論 1 8
  • “尾遞歸優化”的含義是:如果遞歸函數屬于尾遞歸,那么運行時會優化其調用過程。優化主要針對調用棧,將多層調用,轉化為...
    RocWay閱讀 548評論 0 0