程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA編程入門知識 >> java 遞歸深入理解

java 遞歸深入理解

編輯:JAVA編程入門知識
遞歸:一個過程或函數在其定義或說明中有直接或間接調用自身的一種方法,它通常把一個大型復雜的問題層層轉化為一個與原問題相似的規模較小的問題來求解。本案例很清楚的說明了遞歸是如何將一個復雜的問題轉化為規模較小的問題來解決的。下面通過一個小例子來說明遞歸的原理。
代碼如下:

/**
* @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
}
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved