递归与斐波那契数列
? ? ? ? 遞歸是程序設計中經常遇到的概念,一些數學問題經常能用遞歸的方式解決,并且在算法設計中也能用到遞歸。筆者在最近學習算法的過程中,遇到了一種可以用遞歸方式實現的算法——歸并排序,在介紹這個算法之前,有必要先把遞歸的概念介紹一下。所以本篇主要介紹遞歸的概念,并通過它的一個應用——斐波那契數列來說明。
? ? ? ? 遞歸簡單來說就是如果一個函數或方法在執行時,直接或間接地調用了自己,那么這個過程就是遞歸的,這個方法就是遞歸的方法。它通常會把一個大型的復雜的問題一層一層地轉化為一個一個與原問題相似的規模較小的問題,并逐層解決這些較小的問題,最后將整個大的問題解決。
? ? ? ? 遞歸的實現必須滿足一定條件,首先原問題與子問題的處理方式應該一樣,這樣遞歸產生的各個子問題就可以用相同的方式解決;其次,遞歸不能無限遞歸,必須有一個結束的條件,當滿足這個條件時,停止遞歸,返回去逐層解決各個子問題。
? ? ? ? 通常基于遞歸方式編寫的代碼會比基于循環方式實現的代碼簡潔許多,也更加容易實現。但它的缺點也是很明顯的,遞歸是函數或方法不斷調用自身的過程,在這個不斷調用的過程中是需要消耗時間和空間的,每一次的調用都需要在內存棧中分配空間來保存參數、返回地址和臨時變量,同時數據的入棧和出棧都需要時間,這就導致有些時候遞歸的實現效率并不如循環。同時,遞歸就是把一個大的問題不斷分解成各個子問題的過程,這些子問題可能會存在重復的現象,而這些重復就會給程序的性能帶來負面影響,從而影響執行效率。除此以外,遞歸還可能引發更嚴重的問題:棧溢出。前面提到函數或方法的每一次調用都需要在內存棧中分配空間,而每個進程的棧的容量是有限的,當遞歸調用的層級過多時,可能會超出棧的容量,從而導致調用棧溢出。
? ? ? ? 雖然遞歸有一些缺點,但遞歸簡化了程序設計,使程序更容易閱讀和理解,并且隨著科技的不斷發展,計算機的運算性能越來越高,所以能用遞歸方式解決的問題可以優先考慮遞歸。下面介紹一個用遞歸方式解決的經典問題——斐波那契數列。
? ? ? ? 斐波那契數列指的是這樣的一組序列:第1項是0,第2項是1,從第3項開始,每一項的值都等于前兩項之和(即f(n)=f(n-1)+f(n-2))。
? ? ? ??斐波那契數列的數學表示:
? ? ? ? 計算斐波那契數列的第n項,假設n=20。
? ? ? ? 遞歸代碼:
//遞歸方式public static int fibonacci1(int n) {if(n == 0) return 0;else if(n == 1) return 1;else return fibonacci1(n-1) + fibonacci1(n-2);}? ? ? ? 可以看到遞歸方式實現斐波那契數列的代碼非常簡潔,但仔細研究會發現,求f(20)得先求出f(19)和f(18),求f(19)得先求出f(18)和f(17),求f(18)得先求出f(17)和f(16)……以此類推可以發現,里面有重復的求值操作,比如f(18)、f(17)等都計算了兩次。當數據量很大時,重復的求值操作會非常多,就像前面所說,這就影響了程序的執行效率。當然,我們也可以使用非遞歸的方式。
? ? ? ? 非遞歸代碼:
//非遞歸方式public static int fibonacci2(int n) {if(n == 0) return 0;else if(n == 1) return 1;int a = 0, b=1, c = 0;for (int i = 2; i <= n; i++) {c = a+b;a = b;b = c;}return c;}? ? ? ? 這樣就解決了重復計算的問題,但本文主要研究的是用遞歸方式。
? ? ? ? 完整代碼:以Java為例。
/** 斐波那契數列*/ public class Fibonacci {//遞歸方式public static int fibonacci1(int n) {if(n == 0) return 0;else if(n == 1) return 1;else return fibonacci1(n-1) + fibonacci1(n-2);}//非遞歸方式public static int fibonacci2(int n) {if(n == 0) return 0;else if(n == 1) return 1;int a = 0, b=1, c = 0;for (int i = 2; i <= n; i++) {c = a+b;a = b;b = c;}return c;}public static void main(String[] args) {System.out.println("斐波那契數列第20項為:"+fibonacci1(20));System.out.println("斐波那契數列第20項為:"+fibonacci2(20));} }? ? ? ??運行結果:
斐波那契數列第20項為:6765 斐波那契數列第20項為:6765?
? ? ? ? 轉載請注明出處?http://www.cnblogs.com/Y-oung/p/7835180.html
? ? ? ??工作、學習、交流或有任何疑問,請聯系郵箱:yy1340128046@163.com
轉載于:https://www.cnblogs.com/Y-oung/p/7835180.html
總結
- 上一篇: python 学习笔记(十二) 文件和序
- 下一篇: 【Codeforces Round #4