遞歸原來可以so easy|-連載(1)

引子

從前有座山,山上有座廟,廟裏有個老和尚,老和尚在給小和尚講故事,故事講的是從前有座山,山上有座廟,廟裏有個老和尚,老和尚在給小和尚講故事,故事講的是從前有座山,山上有座廟,廟裏有個老和尚,老和尚在給小和尚講故事,故事講的是從前有座山,山上有座廟,廟裏有個老和尚,老和尚在給小和尚講故事,故事講的是從前有座山,山上有座廟,廟裏有個老和尚,老和尚在給小和尚講故事,故事講的是......

這個例子,如果用java程序來演示,會是這個樣子:

public class Hello {
    public static void main(String[] args) {
        sayStory();       
    }

    static void sayStory(){
        System.out.println("從前有座山,山上有座廟,廟裏有個老和尚,老和尚在給小和尚講故事,故事講的是");
        sayStory();
    }   
}

程序運行結果:

遞歸原來可以so easy|-連載(1)

故事在一直講下去。

看一下java代碼中,在方法sayStory()中又調用了sayStory()。

遞歸概述

什麼是遞歸

  遞歸,英文爲Recursion, 在計算機科學中,遞歸指得是在函數的定義中使用函數自身。
遞歸,包含了兩個意思:遞 和 歸。遞是隻傳遞下去,歸是指歸來,也就是說,遞歸有去也有回。
那麼,上面的講故事的程序,算遞歸程序嗎?
在方法sayStory()中又調用了sayStory(),符合遞歸的一個條件,即傳遞,但是,這個程序,沒有歸來,所以,程序會一直運行下去,直到資源耗盡,程序出錯:

遞歸原來可以so easy|-連載(1)

因此,這不是個完整的遞歸程序。
遞歸要素
首先,遞歸必須要申明一個函數,且在函數中調用自身。
另外,遞歸要有明確的終止條件,遞歸就是有去有回,必然有一個明確的重點,到達這個終點後,就不再往下遞,而是開始往回歸來。

遞歸的內涵

​ 遞歸的核心思想,就是把規模大的問題轉化爲規模小的相似的子問題來解決。在函數實現時,因爲解決大問題的方法和解決小問題的方法往往是同一個方法,所以就產生了函數調用它自身的情況,這也正是遞歸的定義所在。
考慮一下,遞歸的數學模型,很像數學歸納法。數學歸納法適用於將解決的原問題轉化爲解決它的子問題,而它的子問題又變成子問題的子問題。歸納法解決數學問題一般分爲下面3個步驟:
1:步進表達式:問題演算成子問題的表達式
2:結束條件:什麼時候可以不再使用步進表達式
3:求解表達式:在結束條件下能夠直接計算返回值的表達式

比如,斐波那契數列,使用數學歸納法,3個步驟爲:
1: 推導出計算表達式: F(n)=F(n-1)+F(n-2) (n≥3)
2:結束條件:n=1,n=2時
3:求解表達式: F(1)=F(2)=1

遞歸的編程模型

   明確了遞歸的數學模型後,我們就要看,如果通過編程來實現遞歸。一般的,有兩種編程模型:

模型一: 先處理問題,然後再往下傳遞
遞歸函數(大規模){

    if (end_condition){      // 遞歸終止條件
        end;   
    }else{
        solve;             // 處理問題
        遞歸函數(小規模);  // 分解問題規模,傳遞下去
    }
}

模型二: 在歸來的過程中處理問題
遞歸函數(大規模){

    if (end_condition){      // 遞歸終止條件
        end; 
}else{ 
    遞歸函數(小規模);  //分解問題規模,傳遞下去
        solve;            // 歸來,處理問題
    }
}

下面,演示一下,使用遞歸的編程模型,解決斐波那契數列問題。
首先,需要什麼一個函數,問題規模爲n,問題的結果爲一個整數。
則函數可以聲明爲:int fib(int n)
然後,確定終止條件: n=1,n=2時
3:求解表達式:
F(n)=F(n-1)+F(n-2) (n≥3)
F(1)=1,F(2)=1

則代碼如下:

遞歸原來可以so easy|-連載(1)

案例演示

階乘

階乘n!的數學定義: n!=1234…..(n-1)n,並規定 1!=1。
因此,2!=21=2(1!),3!=3(21)=3(2!),
4!=4
(321)=4(3!)
5!=5
(4321)=54!
根據規律,可以推斷出: n!=n*(n-1)!,這就是階乘的遞歸公式。
並且可以明確遞歸的終止條件n=1,終止時的值爲1。

下面,想一下,如何用java程序來實現呢?
遞歸函數原型,可以什麼爲:int factorial(int n);
則函數的遞歸調用表達式爲: factorial(n)=n* factorial(n-1)

具體代碼如下:

public class Hello {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入n:");
        int n = sc.nextInt();
        int f = factorial(n);
        System.out.println("結果是:" + f);
    }

    static int factorial(int n) {
        if (n == 1)
            return 1;
        else
            return n * factorial(n - 1);
    }
}

更多案例,請看下一章節。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章