遞推與遞歸
本文中部分内容轉自他人部落格,作者相關資訊以及部落格位址在文末。
概念
- 遞歸:從已知問題的結果出發,用疊代表達式逐漸推算出問題的開始的條件,即順推法的逆過程,稱為遞歸。
- 遞歸的定義:在一個函數的定義中又直接或間接地調用本身。
- 遞歸思想: 把規模大的、較難解決的問題變成規模較小的、易解決的同一問題。規模較小的問題又變成規模更小的問題,并且小到一定程度可以直接得出它的解,進而得到原來問題的解。
- 遞歸優點: 符合人的思維方式,遞歸程式結構清晰,可讀性,容易了解
- 遞歸缺點: 通過調用函數實作,當遞歸層數過多時,程式的效率低。例如求Fibonacii數列的第1000項?
- 遞歸的應用場合:
1、資料的定義形式是遞歸的,例如求Fibonacii數列的第n項 。
2、資料之間的邏輯關系(即資料結構)是遞歸的,如樹、圖等的定義和操作。
3、某些問題雖然沒有明顯的遞歸關系或結構,但問題的解法是不斷重複執行一組操作,隻是問題規模由大化小,直至某個原操作(基本操作)就結束。例如:漢諾塔問題。
- 遞歸設計的要素:
1、在函數中必須有直接或間接調用自身的語句;
2、在使用遞歸政策時,必須有一個明确的遞歸結束條件,稱為遞歸出口(或遞歸邊界)。
編寫遞歸算法時,首先要對問題的以下三個方面進行分析:
- 決定問題規模的參數。
需要用遞歸算法解決的問題,其規模通常都是比較大的,在問題中決定規模大小(或問題複雜程度)的量有哪些?把它們找出來。
- 問題的邊界條件及邊界值。
在什麼情況下可以直接得出問題的解?這就是問題的邊界條件及邊界值。
- 解決問題的通式。
把規模大的、較難解決的問題變成規模較小、易解決的同一問題,需要通過哪些步驟或公式來實作?這是解決遞歸問題的難點。把這些步驟或公式确定下來。
- 遞推:遞推算法是一種用若幹步可重複運算來描述複雜問題的方法。遞推是序列計算中的一種常用算法。通常是通過計算機前面的一些項來得出序列中的指定象的值。
- 遞推:數學推導 發現規律 重複簡單運算
- 遞歸與遞推差別:相對于遞歸算法,遞推算法免除了資料進出棧的過程,也就是說,不需要函數不斷的向邊界值靠攏,而直接從邊界出發,直到求出函數值。
算法舉例1
- 斐波那契數列:已知f(1) = 1 , f(2) = 1 , 且滿足關系式f(n) = f(n-1) + f(n-2),則f(50)等于多少?
- 分析:根據初始條件f(1) = 1 , f(2) = 1 和關系式f(n) = f(n-1) + f(n-2),可知,f(3) = f(2) + f(1) , f(3) = f(2) + f(1) …….
- 編寫代碼(遞歸)
public class Fibonacci {
static int fun(int n){
if(n == 1 || n == 2){
return 1 ;
}else{
return fun(n-1) + fun(n-2) ;
}
}
public static void main(String[] args) {
for(int i = 1 ; i <= 15 ; ++i)
System.out.println(fun(i));
}
}
- 編寫代碼(遞推)
static int fun2(int n){
int a[] = new int[20] ;
a[1] = 1 ;
a[2] = 1 ;
for(int i=3 ; i<=n ;i++){
a[i] = a[i-1] + a[i-2] ;
}
return a[n] ;
}
- 運作結果:
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
算法舉例2
- 使用遞歸計算1+2+…+100 ;
- 分析:遞歸關系為f(n) = f(n-1) + n ,遞歸出口為f(1) = 1 ;
- 編寫代碼(遞歸):
public class Sum {
static int fun(int n){
if( n == 1){
return 1 ;
}else{
return fun(n-1) + n ;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(fun(100));
}
}
- 編寫代碼(遞推)
static int fun2(int n){
int a[] = new int [200] ;
a[1] = 1 ;
for(int i=2 ; i<=n ; i++){
a[i] = a[i-1] + i ;
}
return a[n] ;
}
- 運作結果:
5050
算法舉例3
- 爬樓問題:假設有n階樓梯,每次可爬1階或2階,則爬到第n層有幾種方案?
- 問題分析:
- 假設一階時隻有一種方案f(1) = 1 ;
- 二階時有兩種方案(即一次走一階和一次走兩階)f(2) = 2 ;
- 三階時有3種 f(3) = 3 ;
- 四階時有五種 f(5) = 5 ;
- 發現遞歸規律f(n) = f(n-1) + f(n-2) ;
- 遞歸出口為f(1) = 1、f(2) = 2 ;
- 編寫代碼(遞歸):
public class Ladder {
static int fun(int n){
if(n == 1){
return 1 ;
}else if(n == 2){
return 2 ;
}else{
return fun(n-1) + fun(n-2) ;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(fun(5));
}
}
- 編寫代碼(遞推):
static int fun2(int n){
int a[] = new int [200] ;
a[1] = 1 ;
a[2] = 2 ;
for(int i=3 ; i<=n ;i++){
a[i] = a[i-1] + a[i-2] ;
}
return a[n] ;
}
- 運作結果:
8
由上述例子可知,遞歸的重點是找到遞歸關系和遞歸出口。
遞 推 小 結:
1、遞推是從已知條件開始;
2、遞推必須有明确的通用公式;
3、遞推必須是有限次運算。
遞 歸 小 結:
1. 遞歸:未知的推到已知的,再由此傳回。
2. 基本思想:将複雜的操作分解為若幹重複的簡單操作。
關于遞推與遞歸的文章還有:
1. https://blog.csdn.net/a1046765624/article/details/66530637
2.
---------------------
作者:葉清逸
來源:CSDN
原文:https://blog.csdn.net/u013634252/article/details/80551060
版權聲明:本文為部落客原創文章,轉載請附上博文連結!