遞歸與回溯


遞歸:是調用一個和調用者同名的方法,他並不是一個方法調用自身,而是方法的一個實例調用相同方法的另一個實例。

遞歸分為:尾遞歸,非尾遞歸,間接遞歸以及過分遞歸;

相比於迭代,遞歸的效率低,但是遞歸的解決方案簡單,與源算法邏輯一致性強,使用迭代需要定義一個新的數據結構實現堆棧,迭代應當適用在實時系統。

 

實例:斐波那契數列使用遞歸實現:

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!");
    }
}    

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM