遞歸:是調用一個和調用者同名的方法,他並不是一個方法調用自身,而是方法的一個實例調用相同方法的另一個實例。
遞歸分為:尾遞歸,非尾遞歸,間接遞歸以及過分遞歸;
相比於迭代,遞歸的效率低,但是遞歸的解決方案簡單,與源算法邏輯一致性強,使用迭代需要定義一個新的數據結構實現堆棧,迭代應當適用在實時系統。
實例:斐波那契數列使用遞歸實現:
0,1,1,2,3,5,8, 13, 21, 34, 55, 89 ......
Fib(n) = n 當n < 2時;Fib(n) = Fib(n-2) + Fib(n-1) 其他情況;
在Java中可以直接定義一個函數Fib然后使用迭代實現:
public int Fib(int n) { if(n < 2) { return n; }else { return Fib(n-2) + Fib(n-1); } }
這個方法簡單易懂,但是效率極低,在計算第26個斐波那契數時,大約需要25萬次的調用,計算第31個數時需要接近三百萬個調用,代價很高。
在計算相對較小的數時可以采用遞歸,
在計算較大數據時可以采用迭代實現:
public int iterativeFib(int n) { if(n < 2) { return n; }else { int i = 2, temp, current = 1, last = 0; for(; i <= n;i++) { temp = current; current += last; last = temp; } return current; } }
回溯:從某點出發有很多的道路選擇,但是不清楚那一條道路能有效地解決問題,嘗試一條道路失敗后,返回到岔路口再試另外的道路,我們必須確定所有的路都是可以嘗試的,可以返回的。
一個經典的回溯問題:
八皇后問題:將八個皇后放在一個棋盤上,要求他們不能相互攻擊,規則是一個皇后可以攻擊同一行,同一列以及和他在同一條對角線上的任意皇后。
解決問題的偽代碼:
putQueen(row)
for 同一row的每個位置col
if col可用
把下一個皇后放在col上
if(row < 8)
putQueen(row+1)
else 成功;
取走col上的皇后
算法的java實現如下:
package queen; import java.io.*; public class Queens { static final int squares = 8, norm = squares - 1; static final boolean available = true; static int [] positionInRow = new int[squares]; static boolean [] column = new boolean[squares]; static boolean [] leftDiagonal = new boolean[squares*2 -1]; static boolean [] rightDiagonal = new boolean[squares*2 -1]; static int howMany = 0; public Queens() { //初始化 for(int i = 0;i < squares; i++) { positionInRow[i] = -1; column[i] = available; } for(int i = 0; i < squares*2 -1;i++) { leftDiagonal[i] = rightDiagonal[i] = available; } } static void printBorad(PrintStream out) { System.out.println("第"+howMany+"種擺放方式:"); //循環打印可行解決方案q表示可行位置 for(int i=0;i<squares;i++){ for(int j=0;j<squares;j++){ if(i == positionInRow[j]){ System.out.print("q "); }else System.out.print("* "); } System.out.println(); } } static void PutQueen(int row) { for(int col = 0; col < squares;col++) { if(column[col] == available && leftDiagonal[row+col] == available && rightDiagonal[row - col +norm] == available) { //確認下一個可以放置的位置 positionInRow[row] = col; //找到可放置位置后,確定不可行域 column[col] = !available; leftDiagonal[row+col] = !available; rightDiagonal[row-col+norm] = !available; //遍歷所有的行 if(row < squares - 1) { PutQueen(row+1); }else { printBorad(System.out); ++howMany; } //重置可行域 column[col] = available; leftDiagonal[row+col] = available; rightDiagonal[row-col+norm] = available; } } } static public void main(String[] args) { Queens queens = new Queens(); queens.PutQueen(0); System.out.println("There are " + howMany + " solutions for this problem!"); } }