程序調用自身的編程技巧稱爲遞歸( recursion)。遞歸做爲一種算法在程序設計語言中普遍應用。一個方法或函數在其定義或說明中有直接或間接調用自身的一種方法,它一般把一個大型複雜的問題層層轉化爲一個與原問題類似的規模較小的問題來求解,遞歸策略只須要少許的程序就能夠描述出解題過程所須要的屢次重複計算,大大地減小了程序的代碼量,讓程序更加的簡潔。java
例如求和問題:若要求解S100 = 1 + 2 + 3 + 4 + …. + 100的值,經過循環的方式代碼以下:算法
int sum = 0; for (int i = 1; i <= 100; i++) { sum = sum + i; }
經過遞歸方式是如何求解呢?由 1 + 2 + 3 + 4 + …. + 100 能夠分解爲 ( 1 + 2 + 3 + 4 + …. + 99) + 100,能夠看出
S100 = S99 + 100,能夠得出 Sn = Sn-1 + n。經過遞歸的方式代碼以下:編程
public int sum(int n) { if (n == 1) { return 1; } else { return sum(n - 1) + n; } }
經過遞歸代碼能夠看出,sum() 方法中又調用了其自身,只是將傳入的參數發生改變。這種程序調用自身的方式就是遞歸。函數
什麼樣的問題纔可使用遞歸的方式求解呢?構成遞歸須要具有兩個條件:
(1)子問題與原始問題屬於一樣的事情,兩者的求解方法是相同的,且子問題比原始問題更易求解。
(2)遞歸不能無限制地調用自己,必須有個遞歸出口。遞歸出口對應的情形相對簡單,能夠化簡爲非遞歸情況處理。設計
斐波那契數列(Fibonacci sequence),又稱黃金分割數列、因數學家列昂納多·斐波那契(Leonardoda Fibonacci)以兔子繁殖爲例子而引入,故又稱爲「兔子數列」,指的是這樣一個數列:
一、一、二、三、五、八、1三、2一、3四、……
在數學上,斐波納契數列以以下被以遞推的方法定義:
F(1)=1,F(2)=1,,F(n) = F(n-1) + F(n-2)(n>=3,n∈N*)。code
問題分析:
斐波那契數列的對於原問題F(n)的求解能夠轉爲對F(n-1)、F(n-2)兩個子問題的求解,故符合條件(1)。由F(1)=1,F(2)=1,能夠得出斐波那契數列問題是有遞歸出口的,遞歸出口對應F(1) = 1,F(2) = 1。求解斐波那契數列的代碼以下:遞歸
public class FibonacciSequence { public static void main(String[] args){ System.out.println(Fribonacci(9)); } public static int Fribonacci(int n){ if(n <= 2) return 1; else return Fribonacci(n-1)+Fribonacci(n-2); } }
階乘問題的數學表達式爲:n! = n * (n-1) * (n-2) * …* 1 (n>0)。經過分析能夠得出n! = (n-1)! * n。令F(n) = n!,則F(n) = F(n-1) * n。則階乘問題符合條件(1)。由0! = 1,能夠得出F(0) = 1。則階乘問題符合條件(2),遞歸出口爲F(0) = 1。利用遞歸求解階乘問題代碼以下:ci
int factorial(int n) { int sum = 0; if (0 == n) return 1; else sum = n * factorial(n-1); return sum; }
二叉樹的遍歷代碼以下:數學
/* 前序遍歷算法 */ void PreOderTraverse(BiTree T) { if(T == NULL) return; printf("%c",T->data); //顯示結點數據,能夠更改成其餘對結點操做 PreOderTraverse(T->lchild); //先遍歷左子樹 PreOderTraverse(T->rchild); //最後遍歷右子樹 } /* 中序遍歷遞歸算法 */ void InOderTraverse(BiTree T) { if(T == NULL) return ; InOderTraverse(T->lchild); //中序遍歷左子樹 printf("%c",T->data); //顯示結點數據,能夠更改成其餘對結點的操做 InOderTraverse(T->rchild); //最後中序遍歷右子樹 } /* 後序遍歷遞歸算法 */ void PostOderTraverse(T) { if(T==NULL) return; PostOderTraverse(T->lchild); //先遍歷左子樹 PostsOderTraverse(T->rchild); //再遍歷右子樹 printf("%c",T->data); //顯示結點數能夠更改成其餘對結點數據 }
經過代碼能夠看出,二叉樹的遍歷過程使用遞歸方式實現既有助於理解,又簡化了代碼量。io
使用遞歸求解問題就比如,你手中有一把鑰匙想要打開一扇門。當你打開面前這扇門,看到屋裏面還有一扇門。你走過去,發現手中的鑰匙還能夠打開它,你推開門,發現裏面還有一扇門,你繼續打開它。若干次以後,你打開面前的門後,發現只有一間屋子,沒有門了。而後,你開始原路返回,每走回一間屋子,你數一次,走到入口的時候,你能夠回答出你到底用這你把鑰匙打開了幾扇門。 遞歸算法的應用十分普遍,應用遞歸算法可使你的代碼根據「優雅」。