遞歸算法
遞歸的基本思想是 “自己調用自己” 。
- 遞歸的基本思想:“自己調用自己”,一個使用遞歸技術的方法將會直接或間接的調用自己。
- 利用遞歸可以用簡單程序解決一些復雜問題。比如:斐波那契數列的計算、漢諾塔、快排等。
- 遞歸結構包括兩部分:
- 定義遞歸頭。PS:如果沒有遞歸頭,將陷入死循環,也就是定義遞歸的結束條件。
- 遞歸體。PS:什么時候需要調用自身方法。
遞歸缺陷:
遞歸調用會占用大量的系統堆棧,內存耗用多,在遞歸調用層次多時速度要比循環慢得多,所以使用遞歸時需慎重。
遞歸原理分析圖
使用遞歸計算 5! 階乘
代碼示例:簡單測試:自己調用自己的方法
- 一個方法里可以去調用其他方法
2.自己調用自時,會一直調用,直到占滿系統資源拋出異常。
// 測試遞歸算法
public class TestRecursion01 {
public static void main(String[] args) {
a(3);
}
static void a(int c){
System.out.println("a");
// 一個方法里可以去調用其他方法
b();
// 自己調用自己:會一直調用,直到占滿系統資源拋出異常。
a(3);
}
static void b(){
System.out.println("b");
}
}
代碼示例:使用遞歸計算 n!(對比下方循環效率)
- printf() 輸出函數作用:定義一些變量,用來格式化輸出。
- %n 作用是輸出時實現換行。%n是一種格式字符串,只能用到printf()的參數里。
- %n 是轉義字符,可以用於一切字符串。
// 使用遞歸計算 n!(對比循環效率)
public class TestRecursion {
public static void main(String[] args) {
// 記錄 開始 調用方法進行計算的時刻
long d1 = System.currentTimeMillis();
/**
* printf() 輸出函數作用:定義一些變量,用來格式化輸出。
* %n 作用是輸出時實現換行。%n是一種格式字符串,只能用到printf()的參數里。
* %n 是轉義字符,可以用於一切字符串。
* */
System.out.printf("%d階乘的結果是:%s%n",10,factorial(10));
// 記錄 結束 調用方法進行計算的時刻
long d2 = System.currentTimeMillis();
System.out.printf("遞歸消耗時間是:%s ms%n",d2 - d1); // 耗時: ms
}
// 求階乘的方法
static long factorial(int n){
if (n == 1) {// 遞歸頭
return 1;
}else{ // 遞歸體:factorial(n - 1) 在方法內反復調用自己,直到 n == 1
return n * factorial(n - 1); // n! = n * (n - 1)!
}
// 1*2*3*4*…*9*10
}
}
注意點
- 任何能用遞歸解決的問題也能使用迭代解決。
- 當遞歸方法可以更加自然地反映問題,並且易於理解和調試,並不強調效率問題時,可以采用遞歸。
- 在要求搞性能的情況下盡量避免使用遞歸,遞歸調用既花時間又耗內存。
代碼示例:使用循環計算 n!(對比遞歸效率)
// 使用循環求 n! (對比遞歸效率)
public class TestRecursion02 {
public static void main(String[] args) {
// 記錄 開始 調用方法進行計算的時刻
long d3 = System.currentTimeMillis();
int a = 10;
int result = 1;
while (a > 1){
result *= a * (a-1);
a -= 2;
}
// 記錄 結束 調用方法進行計算的時刻
long d4 = System.currentTimeMillis();
System.out.println("10! 階乘計算結果為:" + result);
System.out.printf("計算消耗時間為:%s ms%n",d4 - d3);
}
}
至此,遞歸算法知識點以及相關效率對比測試到此結束。
