以此類推是遞歸的基本思想。 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的階乘時,遞歸過程以下所示。 排序
咱們會驚奇的發現這個過程和棧的工做原理一致對,遞歸調用就是經過棧這種數據結構完成的。整個過程實際上就是一個棧的入棧和出棧問題。然而咱們並不須要關心這個棧的實現,這個過程是由系統來完成的。 遞歸
那麼遞歸中的「遞」就是入棧,遞進;「歸」就是出棧,迴歸。 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); }
遞歸調用的過程像樹同樣,經過觀察會發現有不少重複的調用。
歸併排序
歸併排序也是遞歸的典型應用,其思想:將序列分爲若干有序序列(開始爲單個記錄),兩個相鄰有序的序列合併成一個有序的序列,以此類推,直到整個序列有序。
//遞歸過程是:在遞進的過程當中拆分數組,在迴歸的過程合併數組 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]; } }
一樣調用過程向樹同樣,可是它並無重複調用的問題。在遞進的過程當中拆分數組,在迴歸的過程合併數組 。經過遞歸來實現歸併排序,程序結構和條理很是清晰。