10.3.1 遞歸的概念
在數學和計算機科學中,遞歸是一種思路和政策,可以用于術語的定義(什麼是表達式),問題的描述和問題求解。
作為一種思路和政策,遞歸與分而治之(divide-and-conquer)互為因果。遞歸
- 可以用于術語的定義(如什麼是表達式),
- 可以用于問題的描述(數學中的分段函數),
- 可以用于問題求解(程式設計中的遞歸調用)。稱為遞歸算法,簡稱遞歸法,後面直接叫遞歸。
遞歸是指用自己的較簡單的情形定義自己。有一個故事。實體學家計算10!時會說,“看,它等于1*2*~*10,即3628800”;數學家則說:“哦,10的階乘,它等于10乘以9!”。
遞歸算法“輕率地”認為自己的較簡單的情形是已知的。既然fact(n-1)是已知的,因而fact(n) 可求。這樣“輕率”對了解遞歸概念至關重要。遞歸法不直接解決問題,而是将問題變成一個趨向遞歸出口的問題。使用遞歸方法需要存在一個基準情形,以避免無限循環(狗追自己的尾巴)。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0NXYFhGd192UvwVe0lmdhJ3ZvwFM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2Lc1TPR5kMBpWTxZEWlZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39TN3gTO1EDNwADNwATM0EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
package algorithm.recursion;
public class RecursionDemo{
/**
* 遞歸求Fibonacci級數的第n個元素,n基于1的自然數。
*/
public static int fibonacc(int n){
if(n<=1) return n;//base case
else return fibonacc(n-1)+fibonacc(n-2);
}
/**
* 疊代求Fibonacci級數的第n個元素,n基于1的自然數。
*/
public static int fibonacc1(int n){
int first , second ,result ;
first =second=result= 1;
for(int i=3;i<=n ;i++){
result = first + second;
first = second;
second =result;
}
return result;
}
}
大多數情況下,疊代法和遞歸法能夠互相轉化。
使用遞歸法有2條實踐準則:
1、設計優先。在任何情況下都可以采用遞歸法,簡潔而清晰的程式設計優先。某些問題,例如那些需要後退的問題(如找出迷宮的出路、對樹的一些操作),如果不采用遞歸則很難解決。
2、 效率平衡。如果遞歸調用中出現重複性工作,改用循環。對于一般的數值計算,遞歸法通常不合适。
Java遞歸方法是通過方法調用棧實作的。在BlueJ中設定斷點運作factorial (5),将顯示方法調用情況。它僅僅“輕率地認為”factorial (4)已知,依此類推。到factorial (5),目前沒有進行任一乘法計算。方法調用棧中有6個棧幀,頂層将計算factorial (0)。遞歸的方法的兩個階段是遞推和回歸。
例如使用遞歸式sum(n) =n + sum(n-1),yqj2065看見過一個趣題。
static long sum1(long a) {
return (a == 1)? 1:(a + sum1(a - 1));
}
static long sum2(long a) {
return (a == 1)? 1:(sum2(a - 1) + a);
}
兩者有差別嗎?【注:在Java7時sum1(6000)StackOverflowError,Java8到大約13000才溢出。 原因不明。】
《程式設計導論(Java)·10.3.2 案例:漢諾塔問題》
練習:
1.Given a non-negative int n, return the sum of its digits recursively (no loops). Note that mod (%) by 10 yields the rightmost digit (126 % 10 is 6), while divide (/) by 10 removes the rightmost digit (126 / 10 is 12).
sumDigits(126) → 9
sumDigits(49) → 13
sumDigits(12) → 3
類似的: 遞歸求一個非負int包含的5的個數。
2.小朋友排排坐,單号伸出2手指,雙号伸出3手指,遞歸求n個小朋友時手指的總數。
sum(0) → 0
sum(1) → 2
sum(2) → 5