一、遞歸函數,通俗的說就是函數本身自己呼叫自己...
如:n!=n(n-1)!
你定義函數f(n)=nf(n-1)
而f(n-1)又是這個定義的函數。 。這就是遞迴
二、為什麼要用遞歸:遞歸的目的是簡化程式設計,讓程式易讀
三、遞歸的弊端:雖然非遞歸函數效率高,但較難編程,可讀性較差。遞歸函數的缺點是增加了系統開銷,也就是說,每遞歸一次,棧記憶體就多佔用一截
四、遞歸的條件:需有完成任務的語句,需滿足遞歸的要求(減小而不是發散)
五、遞歸進階:
1.用遞歸算n的階乘:
分析:n!=n*(n-1)*(n-2)...*1
public int dReturn(int n){ if(n==1){ return 1; }else{ return n*dReturn(n-1); } }
2.用遞歸函數算出1到n的累加:1+2+3+4+..+n
public int dReturn(int n){ if(n==1){ return 1; }else{ return n+dReturn(n-1); } }
3.要求輸出一個序列:1,1,2,3,5,8,11......(每一個數為前兩個數子之和,要求用遞歸函數)
用java遞歸來表示一個函數:F(n)=F(n-1)+F(n-2);F(0)=1;F(1)=1;
分析:X1=1; X2=1; X3=X1+X2; X4=X2+X3; ... ; Xn=X(n-1)+X(n-2)
public int F(int n){ if(n==1){ return 1; }else if(n==2){ return 1; }else{ return F(n-1)+F(n-2); } }
4.java用遞歸方法反向列印一個整數數組中的各個元素
public static void printAll(int index,int[] arr){ System.out.println(arr[index]); if(index > 0){ printAll(--index,arr); } } public static void main(String [] args){ int[] arr={1,2,3,4,5}; printAll(arr.lenth-1,arr); }
5.程式解決方案:若一頭小母牛,從出生起第四年開始每年生一頭母牛,按次規律,第n 年時有多少頭母牛?
public static int cattle(int n){ if(n<=0){ return 0; }else if(n<=3){ return 1; }else{ return cattle(n-1)+cattle(n-3) ; } } public static void main(String[] args){ int n=10; System.out.println(n+"年後共有"+cattle(n)+"頭牛"); }
遞歸、線性遞歸、尾遞歸的概念?
Java中遞歸函數的呼叫-求一個數的階乘
不考慮溢位:一般只能算到69的階乘…
注意:0的階乘0! =1
任何大於1的自然數n階乘表示方法:
n!=1×2×3×……×n
或n!=n×(n-1)!
搜尋0的階乘,可以出來一個線上計算器,很實用哦! !
package test;import java.util.Scanner;public class DiGui {public static void main(String[] args) {// TODO Auto-generated method stubSystem.out.println("輸入整數:");Scanner scan = new Scanner(System.in);int x = scan.nextInt();int result = digui(x);System.out.println(result);}//遞迴函數public static int digui(int x){if(x <=0){return 1;}else{return x*digui(x-1);}}}
遞歸:一個過程或函數在其定義或說明中有直接或間接調用自身的一種方法,它通常把一個大型複雜的問題層層轉化為一個與原問題相似的規模較小的問題來求解。本案例很清楚的說明了遞歸是如何將一個複雜的問題轉化為規模較小的問題來解決的。下面透過一個小例子來說明遞歸的原理。
/*** @fileName Test.java* @description ??????????* @date 2012-11-25* @time 17:30* @author wst*/public class Test { static int multiply( int n) { int factorial; // ?? if ((n == 1) || (n == 0)) { factorial = n; } else { factorial = n * multiply(n - 1); } return factorial ; } public static void main(String[] args) { System.out.println(multiply(5)); }}
當函數被呼叫時,它的變數的空間是創建於運行時堆疊上的。以前調用的函數的變數扔保留在堆疊上,但他們被新函數的變數所掩蓋,因此是不能被存取的。
程式中的函數有兩個變數:參數n和局部變數factorial。下面的一些圖顯示了堆疊的狀態,目前可以存取的變數位於棧頂。所有其他呼叫的變數飾以灰色的陰影,表示他們不能被目前正在執行的函數存取。
假定我們以5這個值呼叫遞歸函數。堆疊的內容如下,棧頂位於最下方:
n multiply(n) factorial 5 multiply(5) 5*multiply(4) //第一次呼叫4 multiply(4) 4*multiply(3) //第二次呼叫3 multiply(3) 3*multiply(2 ) //第三次調用2 multiply(2) 2*multiply(1) //第四次調用1 multiply(1) 1 //第五次調用
從上面的資訊可以很容易的看出,遞歸是如何將一個問題逐漸最小化來解決的,從方法呼叫開始,factorial結果都會被壓入棧,直到方法呼叫結束,最後從棧頂逐個返回得到結果。經過逐一代入,結果如下:
n=1 1 向上返回1
n=2 2*multiply(1) 向上回傳2*1=2
n=3 3*multiply(2) 向上回傳3*(2*1)=6
n=4 4*multiply(3) 向上回傳4*(3*(2*1))=24
n=5 5*multiply(4) 向上回傳5*(4*(3*(2*1)))=120
注意:因為multiply(1)或multiply(0)傳回的值為1
所以就有2*multiply(1)=2*1=2
又因為multiply(2)符合遞迴條件,遞迴後可化為2*multiply(1)
所以就有3*multiply(2)=3*(2*multiply(1))=3*(2*1)=6
因為multiply(3)遞迴後可化為3*multiply(2)
所以multiply(4)=4*multiply(3)=4*(3*multiply(2))=4*(3*(2*1))=24
以此類推,multiply(5)=5*multiply(4)
可化為5*(4*multiply(3))=5*(4*3*(multiply(2)))=5*(4*(3*(2*1)))=120
再來看看字節碼資訊:
public class Test extends java.lang.Object{ public Test(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return static int multiply (int); Code: 0: iload_0 1: iconst_1 //將int型別常數1壓入堆疊2: if_icmpeq 9 //將兩個int型別值比較,相等,則跳到位置9,這就是||的短路功能5: iload_0 //此處是在第一個條件不成立的情況下執行,從局部變數0中裝載int類型值(將n的值壓入堆疊) 6: ifne 14 //比較,如果不等於0則跳到位置14,注意:由於此處預設和0比較,所以沒有必要再將常數0壓入堆疊9: iload_0 //如果在ifne處沒有跳轉,則從局部變數0中裝載int類型值(將n的值壓入堆疊) 10: istore_1 //將int型別值存入局部變數1中(彈出堆疊頂的值即局部變數0壓入堆疊的值,再存入局部變數1中) 11: goto 23 //無條件跳到位置23 14: iload_0 //位置6處的比較,如果不等於0執行此指令,從局部變數0中裝載int類型值(將n的值壓入堆疊) 15 : iload_0 //從局部變數0中裝載int類型值(將n的值壓入堆疊) 16: iconst_1 //將int型別常數1壓入棧,常數1是程式碼中n-1的1 17: isub / /執行減法操作,n-1 18: invokestatic #2; //Method multiply:(I)I,呼叫方法multiply 21: imul //執行乘法操作,n * multiply(n - 1) 22: istore_1 //將int型別值存入局部變數1中,factorial=... 23: iload_1 //從局部變數1裝載int型別值(將factorial的結果壓入堆疊) 24: ireturn //方法回傳public static void main( java.lang.String[]); Code: 0: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream; 3: iconst_5 4: invokestatic #2; //Method multiply:(I )I 7: invokevirtual #4; //Method java/io/PrintStream.println:(I)V 10: return }