java算法1_遞歸

遞歸:方法內部調用方法本身的一種編程技巧。

當一個方法(功能)被重複使用時,如果每一次使用該方法參數都不確定,都是由上次的方法返回的結果來確定的,這個時候就要使用遞歸。

比如:N 的階乘:

package edu.aiai.coll;
import java.util.Scanner;
public class TestRec {
    public static void main(String[] args) {
        System.out.println(fac((new Scanner(System.in)).nextInt()));
    }
    public static int fac(int n){
        if(n==1){
            return 1;
        }else{
            return n*fac(n-1);
        }
    }
}

注意點:

1遞歸必須有明確的出口(如上面代碼中的n等於1時的返回1),不然就會一直遞歸下去,直到程序報StackOverflowError錯誤而終止。

2遞歸調用中各層的執行順序問題:最外層調用內層調用最內層,等最內層執行完畢之後,內層執行,然後最外層執行並返回結果,以上面爲例:如果計算4的階乘,是先算3的階乘,要想算3的階乘,先算2的階乘,想算2的階乘,先算1的階乘,1的階乘返回1fac(2)拿到1之後執行2乘以1,返回2,2的階乘計算完畢,然後是3的階乘,最後是4的階乘,返回結果,即爲我們想要的結果。

按照上面說的執行過程來看一個文件遞歸刪除的例子:

package edu.aiai.coll;
import java.io.File;
public class TestRec {
    public static void main(String[] args) {
        File dir = new File("d:/test");
        delDir(dir);
    }
    public static void delDir(File dir){
        File[] arrFiles = dir.listFiles();
        for(int i=0;i<arrFiles.length;i++){
            if(arrFiles[i].isDirectory()){
                delDir(arrFiles[i]);
            }
            arrFiles[i].delete();
            System.out.println(arrFiles[i]);
        }
        dir.delete();
    }
}

輸出結果爲

d:\test\java\javaSE\BubbleTest.class

d:\test\java\javaSE

d:\test\java\NewFile.xml

d:\test\java\question\api\allclasses-frame.html

d:\test\java\question\api\resources\inherit.gif

d:\test\java\question\api\resources

d:\test\java\question\api

d:\test\java\question\Num01.class

d:\test\java\question

d:\test\java

可以看出,執行過程爲:找的時候逐層向裏面找,執行的時候最裏面先執行然後外面依次執行,最後是最外面執行。

200331618.jpg

上圖簡單畫出了執行順序,和上面文字描述一致。

遞歸另一個需要注意的問題是不要多(>1)處遞歸,這樣會驗證降低效率:

比如菲波那契數列:

package edu.aiai.coll;
public class TestRec {
    public static void main(String[] args) {
        System.out.println(f(10));
    }
    public static int f(int n){
        if(n==1 || n==2){
            return 1;
        }
        return f(n-1)+f(n-2);
    }
}

效率低下原因如下圖:以9爲例:

200608302.jpg

想得到f(9)的值,就得先算f(8)f(7),想得到f(8)的值,就得先算f(7)f(6),依次類推,運算的次數呈幾何級數增長,所以如果數大的話,計算效率會非常低。

這個我們可以通過循環疊加的方法解決:

long n1=1, n2=1;
for(int i=3; i<=50; i++){
    n2 = n1+n2;
    n1 = n2-n1;
}

再說一個著名的遞歸調用的問題:漢諾塔 Towers of Hanoi

package com.anjoyo.hanoi;
import java.util.Scanner;
public class TestHanoi {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        System.out.println("請輸入盤子數量:");
        int niNum = scan.nextInt();
        move(niNum,'A','B','C');
    }
    public static void move(int n,char a,char b,char c){
        if(n==1){
            System.out.println("盤 " + n + " 由 " + a + " 移至 " + c);
        }else{
            move(n - 1, a, c, b);
            System.out.println("盤 " + n + " 由 " + a + " 移至 " + c);
            move(n - 1, b, a, c);
        }
    }
}

關於漢諾塔,這裏再上傳一個ppt,幫助大家理解。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章