一 遞歸
遞歸的基本概念:
程序調用自身的編程技巧稱為遞歸,是函數自己調用自己.一個函數在其定義中直接或間接調用自身的一種方法,它通常把一個大型的復雜的問題轉化為一個與原問題相似的規模較小的問題來解決,可以極大的減少代碼量.遞歸的能力在于用有限的語句來定義對象的無限集合.
利用遞歸可以解決很多問題:如背包問題,漢諾塔問題,斐波那契數列為:0,1,1,2,3,5......等.
遞歸的要素:
- 遞歸就是在過程或函數里面調用自身;
- 在使用遞歸時,必須有一個明確的遞歸結束條件,稱為遞歸出口.
遞歸的步驟:
- 遞推:把復雜的問題的求解推到比原問題簡單一些的問題的求解;
- 回歸:當獲得最簡單的情況后,逐步返回,依次得到復雜的解.
遞歸的優勢:
- 大問題化為小問題,可以極大的減少代碼量;
- 用有限的語句來定義對象的無限集合.;
- 代碼更簡潔清晰,可讀性更好
遞歸的劣勢:
- 遞歸調用函數,浪費空間;
- 遞歸太深容易造成堆棧的溢出;
二 迭代
迭代的概念:
利用變量的原值推算出變量的一個新值.如果遞歸是自己調用自己的話,迭代就是A不停的調用B.
迭代的優點:
- 迭代效率高,運行時間只因循環次數增加而增加;
- 沒什么額外開銷,空間上也沒有什么增加,
迭代的缺點:
- 不容易理解;
- 代碼不如遞歸簡潔;
- 編寫復雜問題時困難。
由于遞歸引起一系列的函數調用,并且有可能會有一系列的重復計算,遞歸算法的執行效率相對較低.
三 辯證看遞歸和迭代
- 遞歸中一定有迭代,但是迭代中不一定有遞歸,大部分可以相互轉換。
- 能用迭代的不用遞歸,遞歸調用函數,浪費空間,并且遞歸太深容易造成堆棧的溢出.
往往有這樣的觀點:能不用遞歸就不用遞歸,遞歸都可以用迭代來代替。
誠然,在理論上,遞歸和迭代在時間復雜度方面是等價的(在不考慮函數調用開銷和函數調用產生的堆棧開銷),但實際上遞歸確實效率比迭代低,既然這樣,遞歸沒有任何優勢,那么是不是就,沒有使用遞歸的必要了,那遞歸的存在有何意義呢?
萬物的存在是需要時間的檢驗的,遞歸沒有被歷史所埋沒,即有存在的理由。從理論上說,所有的遞歸函數都可以轉換為迭代函數,反之亦然,然而代價通常都是比較高的。但從算法結構來說,遞歸聲明的結構并不總能夠轉換為迭代結構,原因在于結構的引申本身屬于遞歸的概念,用迭代的方法在設計初期根本無法實現,這就像動多態的東西并不總是可以用靜多態的方法實現一樣。這也是為什么在結構設計時,通常采用遞歸的方式而不是采用迭代的方式的原因,一個極典型的例子類似于鏈表,使用遞歸定義及其簡單,但對于內存定義(數組方式)其定義及調用處理說明就變得很晦澀,尤其是在遇到環鏈、圖、網格等問題時,使用迭代方式從描述到實現上都變得不現實。因而可以從實際上說,所有的迭代可以轉換為遞歸,但遞歸不一定可以轉換為迭代。
采用遞歸算法需要的前提條件是,當且僅當一個存在預期的收斂時,才可采用遞歸算法,否則,就不能使用遞歸算法。
遞歸其實是方便了程序員難為了機器,遞歸可以通過數學公式很方便的轉換為程序。其優點就是易理解,容易編程。但遞歸是用棧機制實現的,每深入一層,都要占去一塊棧數據區域,對嵌套層數深的一些算法,遞歸會力不從心,空間上會以內存崩潰而告終,而且遞歸也帶來了大量的函數調用,這也有許多額外的時間開銷。所以在深度大時,它的時空性就不好了。
而迭代雖然效率高,運行時間只因循環次數增加而增加,沒什么額外開銷,空間上也沒有什么增加,但缺點就是不容易理解,編寫復雜問題時困難。
因而,“能不用遞歸就不用遞歸,遞歸都可以用迭代來代替”這樣的理解,還是辯證的來看待,不可一棍子打死。
部分摘自網絡,略有改動,向原作者致敬!