Java中遞歸與迭代的區別

Java遞歸與迭代的區別

 在找工作面試的過程中,遇到這樣一個問題:遞歸與迭代的區別?當時感覺這個基礎的問題回答的很差,值回答了簡單的層面意思。所以,回來就查閱資料總結了一下。參考博客:http://blog.csdn.net/laoyang360/article/details/7855860

1. 基本概念

 遞歸:在程序中,一個函數調用自身的編程方法稱爲遞歸。【函數自己調用自己】

 一個函數在其定義中直接或者間接調用自身的一種方法,它通常把一個大型的複雜問題轉化爲一個與原問題相似的小問題來解決。這樣,就可以將問題由複雜——>簡單轉化,可以極大的減少代碼量。遞歸的能力就在於用有限的代碼來定義對象的無限集合。

 使用遞歸應該注意的兩點:

 1) 遞歸就是在過程或者函數裏面調用自身;

 2) 在使用遞歸時,必須有一個明確的遞歸結束條件,稱爲遞歸的出口。這樣能夠防止無限“循環”(自身調用)。

利用遞歸可以解決很多問題:揹包問題、漢諾塔問題、、、等等

 

 迭代:利用變量的原理推算出變量的一個新值。如果說遞歸時自己調用自己,那麼迭代就是A不斷的調用B

 

2. 辯證看待遞歸與迭代

 所謂遞歸,簡言之就是程序自身調用自身,以此來實現層次數據結構的查詢與訪問。在程序中,一個複雜的問題如果能夠用遞歸實現的話,能夠是代碼更加的整潔清楚,可讀性更好。但是,遞歸有一個很嚴重的缺點:由於遞歸需要使用系統的堆棧,所以空間消耗要比非遞歸代碼大很多,而且,如果遞歸深度太大,可能系統資源會不夠用。

 

往往有這樣的觀點:“能不用遞歸就不用遞歸,遞歸都可以用迭代來代替”

 

 在理論上,遞歸和迭代在時間複雜度方面是等價的(在不考慮函數調用開銷和函數調用產生的堆棧開銷),但實際上遞歸確實效率比迭代低。既然這樣,遞歸沒有任何優勢,那麼使用遞歸就沒有必要了,那麼遞歸存在的意義?

 萬物的存在是需要時間的檢驗的,遞歸沒有被歷史所埋沒,即有存在的理由。從理論上說,所有的遞歸函數都可以轉換爲迭代函數,反之亦然,然而代價通常都是比較高的。但從算法結構來說,遞歸聲明的結構並不總能夠轉換爲迭代結構,原因在於結構的引申本身屬於遞歸的概念,用迭代的方法在設計初期根本無法實現,這就像動多態的東西並不總是可以用靜多態的方法實現一樣。這也是爲什麼在結構設計時,通常採用遞歸的方式而不是採用迭代的方式的原因,一個極典型的例子類似於鏈表,使用遞歸定義及其簡單,但對於內存定義(數組方式)其定義及調用處理說明就變得很晦澀,尤其是在遇到環鏈、圖、網格等問題時,使用迭代方式從描述到實現上都變得不現實。因而可以從實際上說,所有的迭代可以轉換爲遞歸,但遞歸不一定可以轉換爲迭代。

 採用遞歸算法需要的前提條件是,當且僅當一個存在預期的收斂時,纔可採用遞歸算法,否則,就不能使用遞歸算法。

 遞歸其實是方便了程序員難爲了機器,遞歸可以通過數學公式很方便的轉換爲程序。其優點就是易理解,容易編程。但遞歸是用棧機制實現的,每深入一層,都要佔去一塊棧數據區域,對嵌套層數深的一些算法,遞歸會力不從心,空間上會以內存崩潰而告終,而且遞歸也帶來了大量的函數調用,這也有許多額外的時間開銷。所以在深度大時,它的時空性就不好了。

 而迭代雖然效率高,運行時間只因循環次數增加而增加,沒什麼額外開銷,空間上也沒有什麼增加,但缺點就是不容易理解,編寫複雜問題時困難。

因而,“能不用遞歸就不用遞歸,遞歸都可以用迭代來代替”這樣的理解,還是辯證的來看待,不可一棍子打死。

以上兩段內容摘自“參考網站作者所寫內容”,像原作者致敬!

 

3. 優缺點總結:

 

 

定義

優點

缺點

遞歸

程序調用自身的編程技巧稱爲遞歸

1)大問題化爲小問題,可以極大的減少代碼量;

2)用有限的語句來定義對象的無限集合.;

3)代碼更簡潔清晰,可讀性更好

1)遞歸調用函數,浪費空間;

2)遞歸太深容易造成堆棧的溢出;

 

迭代

利用變量的原值推算出變量的一個新值,迭代就是A不停的調用B.

1)迭代效率高,運行時間只因循環次數增加而增加;

2)沒什麼額外開銷,空間上也沒有什麼增加,

1 不容易理解;

2 代碼不如遞歸簡潔;

3 編寫複雜問題時困難。

二者關係

1 遞歸中一定有迭代,但是迭代中不一定有遞歸,大部分可以相互轉換。

2 能用迭代的不用遞歸,遞歸調用函數,浪費空間,並且遞歸太深容易造成堆棧的溢出.

 

4. 代碼舉例:斐波那契數列

package test;

public class Main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(fab_recursion(10));
		System.out.println(fab_iteration(10));
	}
	//迭代實現斐波那契
	private static long fab_iteration(int index) {
		if (index ==1 || index == 2) {
			return 1;
		}
		else {
			long f1 = 1l;
			long f2 = 1l;
			long f3 = 0;
			for ( int i = 0; i < index-2; i++) {
				f3 = f1 + f2;//利用變量的原值推算出變量的一個新值
				f1 = f2;
				f2 = f3;
			}
			return f3;
		}
	}
	//遞歸實現斐波那契
	private static long fab_recursion(int index) {
		if (index ==1 || index == 2) {
			return 1;
		}
		else {
			return fab_recursion(index-1) + fab_recursion(index - 2);//遞歸求值
		}
	}
}


發佈了71 篇原創文章 · 獲贊 76 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章