什麼是遞迴
任何呼叫自身的函式成為遞迴。遞迴是從跟數學領域借鑑過來的一種有用的技術,遞迴程式碼通常比迭代程式碼更加簡潔易懂。
例項
以階乘喂例,其遞迴定義如下:
n!=1 n=0
n!=n*(n-1)! n>0
複製程式碼
程式碼實現:
public static void main(String[] args) {
int fact = Fact(5);
System.out.println(fact);
}
static int Fact(int n){
if (n==1){
return 1;
}
if (n==0){
return 1;
}
return n*Fact(n-1);
}
複製程式碼
遞迴視覺化
每次遞迴呼叫都在記憶體中生成一個新的函式副本,一旦函式結束,這些副本就從記憶體中刪除。
遞迴與迭代
遞迴:
- 當達到基本情形時,遞迴終止
- 每次遞迴都需要額外的空間用於棧幀開銷
- 如果無窮遞迴(沒有出口),程式會堆疊溢位
- 某些問題用遞迴更容易解決
迭代:
- 當迴圈條件為假時,迭代終止
- 每次迭代不需要額外空間
- 出現死迴圈後程式會一直迴圈執行
- 求解問題可能沒有遞迴那樣顯而易見
遞迴演算法的經典用例
- 斐波那契數列、階乘
- 歸併排序、快速排序
- 二分查詢
- 樹的遍歷
- 圖的遍歷:深度+廣度
- 動態規劃
- 分治演算法
- 漢諾塔
- 回溯演算法
相關問題
- 漢諾塔謎題 演算法:
- 將源柱最上面的n-1個圓盤移動到輔助柱上
- 將第n個圓盤從源柱移到目的柱。
- 將輔助柱的n-1個圓盤一刀目的柱
- 圓柱最上面的n-1個圓盤移動到輔助柱又可以看成一個新問題,然後以同樣的方式解決。
/**
* @param n 第幾個圓盤
* @param frompeg 源柱
* @param topeg 目標柱
* @param auxpeg 輔助柱
*/
void TowersOfHanoi(int n,char frompeg,char topeg,char auxpeg){
/**
* 如果只有一個圓盤,直接移動並返回
*/
if (n == 1){
System.out.println("move disk 1 from peg"+frompeg+"to peg"+topeg);
}
/**
* 利用C柱做輔助,將A最上面的n-1個圓盤移動到B
*/
TowersOfHanoi(n-1,frompeg,auxpeg,topeg);
/**
* 將剩下的圓盤從A移動到C
*/
System.out.println("move disk from peg"+frompeg+"to peg"+topeg);
/**
* 利用A做輔助,將B上的n-1個圓盤移動到C
*/
TowersOfHanoi(n-1,auxpeg,topeg,frompeg);
}
複製程式碼
- 給定一個陣列,用遞迴方法判定陣列中的元素是否是有序的。
int isArrayInSortedOrder(int[] a,int index){
if (a.length == 1){
return 1;
}
return a[index-1]<=a[index-2]?0:isArrayInSortedOrder(a,index-1);
}
複製程式碼
什麼是回溯
回溯是一種採用分治策略進行窮舉搜尋的方法。
回溯經典用例
- 二進位制串
- 生成k進位制串
- 揹包問題
- 廣義字串
- 哈密頓迴路
- 圖著色問題
相關問題
- 生成所有n位長的字串。假設A[0..n-1]是一個大小為n的陣列。
static void Binary(int n){
if (n<1){
Arrays.stream(A).forEach(s-> System.out.print(s+" "));
}else {
A[n - 1] = 0;
Binary(n - 1);
A[n - 1] = 1;
Binary(n - 1);
}
}
複製程式碼
根據問題規模減小和遞迴求解主定理可以求得時間複雜度為2^n