轉自:https://www.cnblogs.com/xiaosen992608/p/4037682.html
遞歸:
遞歸的概念:方法自身調用自身則稱為遞歸。
遞歸的分類:
間接遞歸:方法A調用方法B,方法B調用方法C,方法C調用方法A。 直接遞歸: 方法A調用方法A。(常用)
遞歸的注意事項:
遞歸一定要出口:結束遞歸的條件。 遞歸次數不要太多。
如果遞歸不結束,則會報錯。
java.lang.StackOverflowError: 棧內存溢出錯誤
遞歸會內存溢出隱患的原因:
方法不停地進棧而不出棧,導致棧內存不足。
遞歸的三個條件:
1). 明確遞歸終止條件
我們知道,遞歸就是有去有回,既然這樣,那么必然應該有一個明確的臨界點,程序一旦到達了這個臨界點,就不用繼續往下遞去而是開始實實在在的歸來。換句話說,該臨界點就是一種簡單情境,可以防止無限遞歸。
2). 給出遞歸終止時的處理辦法
我們剛剛說到,在遞歸的臨界點存在一種簡單情境,在這種簡單情境下,我們應該直接給出問題的解決方案。一般地,在這種情境下,問題的解決方案是直觀的、容易的。
3). 提取重復的邏輯,縮小問題規模*
我們在闡述遞歸思想內涵時談到,遞歸問題必須可以分解為若干個規模較小、與原問題形式相同的子問題,這些子問題可以用相同的解題思路來解決。從程序實現的角度而言,我們需要抽象出一個干凈利落的重復的邏輯,以便使用相同的方式解決子問題。
當邊界條件不滿足時,遞歸前進;當邊界條件滿足時,遞歸返回。
1.階乘
public class Test01 { public static void main(String[] args) { System.out.println(f(5)); } public static int f(int n) { if (1 == n) return 1; else return n*f(n-1); } }
2.斐波納契數列
public static int f(int n) { if (n == 1 || n == 2) { // 遞歸終止條件 return 1; // 簡單情景 } return f(n - 1) + f(n - 2); // 相同重復邏輯,縮小問題的規模 }
3.回文字符串的判斷
public static boolean isPalindromeString_recursive(String s){ int start = 0; int end = s.length()-1; if(end > start){ // 遞歸終止條件:兩個指針相向移動,當start超過end時,完成判斷 if(s.charAt(start) != s.charAt(end)){ return false; }else{ // 遞歸調用,縮小問題的規模 return isPalindromeString_recursive(s.substring(start+1).substring(0, end-1)); } } return true; }
知乎用戶李繼剛(https://www.zhihu.com/question/20507130/answer/15551917)對遞歸和循環的生動解釋:
遞歸:你打開面前這扇門,看到屋里面還有一扇門。你走過去,發現手中的鑰匙還可以打開它,你推開門,發現里面還有一扇門,你繼續打開它。若干次之后,你打開面前的門后,發現只有一間屋子,沒有門了。然后,你開始原路返回,每走回一間屋子,你數一次,走到入口的時候,你可以回答出你到底用這你把鑰匙打開了幾扇門。
循環:你打開面前這扇門,看到屋里面還有一扇門。你走過去,發現手中的鑰匙還可以打開它,你推開門,發現里面還有一扇門(若前面兩扇門都一樣,那么這扇門和前兩扇門也一樣;如果第二扇門比第一扇門小,那么這扇門也比第二扇門小,你繼續打開這扇門,一直這樣繼續下去直到打開所有的門。但是,入口處的人始終等不到你回去告訴他答案。