看似簡單的遞歸,你真的理解嗎?

遞歸:

遞歸的概念:

方法自身調用自身則稱爲遞歸。java

遞歸的分類:

  • 間接遞歸:方法A調用方法B,方法B調用方法C,方法C調用方法A。
  • 直接遞歸: 方法A調用方法A。(經常使用)

遞歸的注意事項:

  • 遞歸必定要出口:結束遞歸的條件。
  • 遞歸次數不要太多。

若是遞歸不結束,則會報錯。

java.lang.StackOverflowError: 棧內存溢出錯誤

遞歸會內存溢出隱患的緣由:

方法不停地進棧而不出棧,致使棧內存不足。方法不停地進棧而不出棧,致使棧內存不足。

遞歸的三個條件:

1). 明確遞歸終止條件程序員

   咱們知道,遞歸就是有去有回,既然這樣,那麼必然應該有一個明確的臨界點,程序一旦到達了這個臨界點,就不用繼續往下遞去而是開始實實在在的歸來。換句話說,該臨界點就是一種簡單情境,能夠防止無限遞歸。算法

2). 給出遞歸終止時的處理辦法編程

   咱們剛剛說到,在遞歸的臨界點存在一種簡單情境,在這種簡單情境下,咱們應該直接給出問題的解決方案。通常地,在這種情境下,問題的解決方案是直觀的、容易的。ide

3). 提取重複的邏輯,縮小問題規模*函數

   咱們在闡述遞歸思想內涵時談到,遞歸問題必須能夠分解爲若干個規模較小、與原問題形式相同的子問題,這些子問題能夠用相同的解題思路來解決。從程序實現的角度而言,咱們須要抽象出一個乾淨利落的重複的邏輯,以便使用相同的方式解決子問題。指針

當邊界條件不知足時,遞歸前進;當邊界條件知足時,遞歸返回。code

下面經過示例程序來講明:
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;
}

遞歸和循環的解釋:

遞歸:你打開面前這扇門,看到屋裏面還有一扇門。你走過去,發現手中的鑰匙還能夠打開它,你推開門,發現裏面還有一扇門,你繼續打開它。若干次以後,你打開面前的門後,發現只有一間屋子,沒有門了。而後,你開始原路返回,每走回一間屋子,你數一次,走到入口的時候,你能夠回答出你到底用這你把鑰匙打開了幾扇門。

循環:你打開面前這扇門,看到屋裏面還有一扇門。你走過去,發現手中的鑰匙還能夠打開它,你推開門,發現裏面還有一扇門(若前面兩扇門都同樣,那麼這扇門和前兩扇門也同樣;若是第二扇門比第一扇門小,那麼這扇門也比第二扇門小,你繼續打開這扇門,一直這樣繼續下去直到打開全部的門。可是,入口處的人始終等不到你回去告訴他答案。

遞歸的解釋:

遞歸實際上是方便了程序員難爲了機器,遞歸能夠經過數學公式很方便的轉換爲程序。其優勢就是易理解,容易編程。但遞歸是用棧機制實現的,每深刻一層,都要佔去一塊棧數據區域,對嵌套層數深的一些算法,遞歸會力不從心,空間上會之內存崩潰而了結,並且遞歸也帶來了大量的函數調用,這也有許多額外的時間開銷。因此在深度大時,它的時空性就很差了。(會佔用大量的內存空間)

而迭代雖然效率高,運行時間只因循環次數增長而增長,沒什麼額外開銷,空間上也沒有什麼增長,但缺點就是不容易理解,編寫複雜問題時困難。

能不用遞歸就不用遞歸,遞歸均可以用迭代來代替。(要辯證的看待這個問題,深度不大,仍是能夠採用遞歸的)。

相關文章
相關標籤/搜索