我以前寫過關於遞歸算法的博文,但做爲編程思想系列的文章不得再也不對它進行進一步深刻的剖析。因爲它是一種簡單、常常使用又重要的一種編程思想。java
舉一個通俗的樣例:
有一個8倆重的蘋果要你切成重量相等的若干份。每一份的重量不能大於1倆。你確定會想到這樣作:
1.第一刀先把一個蘋果切成重量均等的2份A1和A2;
2.再把當中的一份A1切成重量均等的兩份A11和A12, 把A2切成均等的兩份A21和A22。
3.把A11切成均等的兩份……
4.直到每一小份都小於等於1倆爲止。
以上的樣例就是遞歸一個模型。把一個大的事物化成若干個小的事物,每一次使用的方法都一樣。code
更爲專業的定義:
程序自身調用自身的編程技巧稱爲遞歸( recursion)。遞歸有直接遞歸和間接遞歸
•直接遞歸:函數在運行過程當中調用自己。
•間接遞歸:函數在運行過程當中調用其餘函數再通過這些函數調用自己。
遞歸有四個特性:
1.必須有可終於達到的終止條件。不然程序將陷入無窮循環。
2.子問題在規模上比原問題小,或更接近終止條件;
3.子問題可經過再次遞歸調用求解或因知足終止條件而直接求解;
4.子問題的解應能組合爲整個問題的解。
上面的樣例中也知足以上的四點性質:
(1).終止條件是每一份的重量不能大於1倆。(2).每一次切的大小都比上一次小;(3).每一次切的方式都一樣,因此子問題可遞歸調用;(4).終於切成的每一小份也就是要求的解。
對上面樣例的實現:
public static void sliceApple(float weight, int times){ if (weight <= 1) { //System.out.println("weight:" + weight); } else { float w = weight / 2; System.out.println("第" + times + "次等分的重量爲:" + w + " " + w); times += 1; sliceApple(w, times); sliceApple(w, times); } } public static void main(String args[]) { sliceApple(8, 1); }
結果:
第1次等分的重量爲:4.0 4.0
第2次等分的重量爲:2.0 2.0
第3次等分的重量爲:1.0 1.0
第3次等分的重量爲:1.0 1.0
第2次等分的重量爲:2.0 2.0
第3次等分的重量爲:1.0 1.0
第3次等分的重量爲:1.0 1.0
將大問題分解成小問題。將複雜的問題簡單化。
使程序更易於理解。加強可讀性。
分析問題,看看問題是否屬於遞歸模型。是否能用遞歸模型解決。一個問題是否能用遞歸模型就看它是否知足遞歸的四個特性。
遞歸在調用的時候要保存調用點的信息。所以會有調用開銷。在對效率有較高要求的時候,假設能用循環解決這個問題最好不要用遞歸。因爲循環沒有調用開銷。效率會更高。
關於遞歸的不少其餘應用可閱讀以前寫的一篇文章:遞歸算法