深刻理解遞歸

遞歸的思想

以此類推是遞歸的基本思想。 java

具體來說就是把規模大的問題轉化爲規模小的類似的子問題來解決。在函數實現時,由於解決大問題的方法和解決小問題的方法每每是同一個方法,因此就產生了函數調用它自身的狀況。另外這個解決問題的函數必須有明顯的結束條件,這樣就不會產生無限遞歸的狀況了。 算法

遞歸的兩個條件 數組

  • 能夠經過遞歸調用來縮小問題規模,且新問題與原問題有着相同的形式。(自身調用)
  • 存在一種簡單情境,可使遞歸在簡單情境下退出。(遞歸出口)

遞歸算法的通常形式數據結構

func( mode){
    if(endCondition){      //遞歸出口
          end;
    }else{
         func(mode_small)  //調用自己,遞歸
    }
}

求一個數的階乘是練習簡單而典型的例子,階乘的遞推公式爲:factorial(n)=n*factorial(n-1),其中n爲非負整數,且0!=1,1!=1 函數

咱們根據遞推公式能夠輕鬆的寫出其遞歸函數:blog

    public static long factorial(int n) throws Exception {
        if (n < 0)
            throw new Exception("參數不能爲負!");
        else if (n == 1 || n == 0)
            return 1;
        else
            return n * factorial(n - 1);
    }

遞歸的過程

在求解6的階乘時,遞歸過程以下所示。 排序

clip_image001

咱們會驚奇的發現這個過程和棧的工做原理一致對,遞歸調用就是經過棧這種數據結構完成的。整個過程實際上就是一個棧的入棧和出棧問題。然而咱們並不須要關心這個棧的實現,這個過程是由系統來完成的。 遞歸

那麼遞歸中的「遞」就是入棧,遞進;「歸」就是出棧,迴歸ip

咱們能夠經過一個更簡單的程序來模擬遞進和迴歸的過程:get

    /**
     * 關於 遞歸中 遞進和迴歸的理解
     * @param n
     */
    public static void recursion_display(int n) {
        int temp=n;//保證先後打印的值同樣
         System.out.println("遞進:" + temp);
        if (n > 0) {
            recursion_display(--n);
        }
        System.out.println("迴歸:" + temp);
    }

遞歸的例子

斐波那契數列

斐波那契數列的遞推公式:Fib(n)=Fib(n-1)+Fib(n-2),指的是以下所示的數列:

一、一、二、三、五、八、1三、21.....

按照其遞推公式寫出的遞歸函數以下:

    public static int fib(int n) throws Exception {
        if (n < 0)
            throw new Exception("參數不能爲負!");
        else if (n == 0 || n == 1)
            return n;
        else
            return fib(n - 1) + fib(n - 2);
    }

遞歸調用的過程像樹同樣,經過觀察會發現有不少重複的調用

image

歸併排序

歸併排序也是遞歸的典型應用,其思想:將序列分爲若干有序序列(開始爲單個記錄),兩個相鄰有序的序列合併成一個有序的序列,以此類推,直到整個序列有序。

    //遞歸過程是:在遞進的過程當中拆分數組,在迴歸的過程合併數組
    public static void mergeSort(int[] source, int[] temp, int first, int last) {
        if (first < last) {
            int mid = (first + last) / 2;
            mergeSort(source, temp, first, mid);    //歸併排序前半個子序列
            mergeSort(source, temp, mid + 1, last); //歸併排序後半個子序列
            merge(source, temp, first, mid, last);    //在迴歸過程當中合併
        } else if (first == last) {                    //待排序列只有一個,遞歸結束
            temp[first] = source[first];
        }
    }

一樣調用過程向樹同樣,可是它並無重複調用的問題。在遞進的過程當中拆分數組,在迴歸的過程合併數組 。經過遞歸來實現歸併排序,程序結構和條理很是清晰。

clip_image002

相關文章
相關標籤/搜索