1. 程式人生 > 實用技巧 >資料結構與演算法--遞迴

資料結構與演算法--遞迴

遞迴(Recursion)

簡單的說,遞迴就是方法自己呼叫自己,每次呼叫時傳入不同的變數,有助於開發者解決複雜問題同時使程式碼更加簡潔!

遞迴小案例

階乘問題:

public static int factorial(int n){
        if(n == 1){
        retern 1;
  }else{
        retern factorial(n - 1) * n;
  }
}

遞迴應用場景

  1.各種數學問題:八皇后,漢諾塔,迷宮,階乘,球和籃子 等等;

  2.各種演算法中使用遞迴:快速排序,歸併排序,二分查詢,分治演算法 等等

  3.把用棧解決的問題使用遞迴替代可以簡化程式碼;

遞迴遵守的規則

  1.執行一個方式時,就會建立一個新的**受保護的獨立空間(棧)**;

  2.方法的區域性變數是獨立的,不會相互影響;

  3.如果方法中使用的是**應用資料型別,就會共享應用資料的資料**;

  4.遞迴**必須向退出遞迴的條件靠近**,否則就是個死迴圈,最終出現StackOverflowError異常;

  5.當一個方法執行完畢,或者**遇到return**,就會返回,遵守誰呼叫就把結果返回給誰,當方法執行完畢或者返回,改方法也就執行完畢;

回溯

回溯是一種優搜尋法,按選優條件向前搜尋,達到目標,擔當搜尋到某一步時發現原來得選擇並不優或打不到目標,就退回一步重新選擇

回溯與遞迴的區別

遞迴是一種演算法結構。遞迴出現在子程式中,形式上表現為直接或間接地自己呼叫自己。

回溯是一種演算法思想,是使用遞迴實現的。回溯的過程類似於窮舉法,但回溯有“剪枝”(自我判斷)的功能;

八皇后問題

  八皇后問題是一個古老而著名的問題,是回溯演算法的典型案例:要求:在8x8的國際象棋上擺放八個皇后,使

  其不能互相攻擊,即:任意兩個皇后都不能出於同一行,同一列,同一斜線上,問共有多少種擺法!!

思路:

  1.第一個皇后先放在第一行第一列

  2.第二個皇后放在第二行第一列,然後判斷是否ok,不ok,放在第二列,第三列... ,依次放完所有列,直到找到一個合適的;

  3.第三個皇后放在第三行第一列,第二列 ... ,直到第八個皇后也找到不衝突的位置。得到正確解。

  4.當得到正確解之後,棧退回到上一個棧時,就開始回溯,即將第一個皇后放到放到第一列的所有正解全部得到。

  5.然後返回繼續將第一個皇后放到第二列,後面繼續迴圈執行1,2,3,4的步驟。

        public class Queue8 {
//定義一個max:表示共有多少個皇后
int max = 8;
int[] array = new int[max]; //儲存皇后放置的結果
static int count = 0;
static int judgeCount = 0;
public static void main(String[] args) {
    Queue8 queue8 = new Queue8();
    queue8.check(0);
    System.out.printf("共有%d種解法\n",count);
    System.out.printf("判斷衝突的次數:%d次",judgeCount);
}

//放置第n+1個皇后
private void check(int n){
    if (n == max){
        print();
        return;
    }
    //依次放入皇后,並判斷是否衝突
    for (int i = 0; i < max; i++) {
        //先把當前的皇后n 放到該行的第一列
        array[n] = i;
        //判斷放置第n個皇后到i列時,是否衝突
        if (judge(n)){
            //放n+1個皇后,(遞迴)
            check(n+1);
        }
        //如果衝突,就繼續執行array[n]=i(將第n個皇后放置在本行後移的一個位置)
    }
}
//檢視當我們放置第n個皇后,就去檢測該皇后是否和前面已經擺放好的衝突

/**
 *
 * @param n 表示第n個皇后
 * @return
 */
private boolean judge(int n){
    judgeCount++;
    for (int i = 0; i < n; i++) {
        /**
         * array[i] == array[n]:表示判斷 第n個皇后和前面的 n- 1皇后是否在同一列
         * Math.abs(n-i) == Math.abs(array[n]-array[i]:表示判斷第n個皇后是否和第i個皇后在同一斜線
         */
        if (array[i] == array[n] || Math.abs(n-i) == Math.abs(array[n]-array[i])){
            return false; //衝突
        }
    }
    return true;  //表示不衝突
}
//將皇后擺放的位置輸出
private void print(){
    count++;
    for (int i = 0; i < array.length; i++) {
        System.out.print(array[i]+" ");
    }
    System.out.println();
}}

結果:

  解法共有 92 種,judge共執行 15720 次!