loop、iterate、traversal和recursion這幾個詞是計算機技術書中常常會出現的幾個詞彙。衆所周知,這幾個詞分別翻譯爲:循環、迭代、遍歷和遞歸。乍一看,這幾個詞好像都與重複(repeat)有關,但有的又好像不徹底是重複的意思。那麼這幾個詞到底各是什麼含義,有什麼區別和聯繫呢?下面就試着解釋一下。程序員
有了以上定義,這幾個概念之間的區別其實就比較清楚了。至於它們之間的聯繫,嚴格來說,它們彷佛都屬於算法的範疇。換句話說,它們只不過是解決問題的不一樣手段和方式,而本質上則都是計算機編程中達成特定目標的途徑。算法
迭代算法是用計算機解決問題的一種基本方法。它利用計算機運算速度快、適合作重複性操做的特色,讓計算機對一組指令(或必定步驟)進行重複執行,在每次執行這組指令(或這些步驟)時,都從變量的原值推出它的一個新值。編程
利用迭代算法解決問題,須要作好如下三個方面的工做:數組
能夠用迭代的算法有很經典的問題,好比兔子產子問題:假定你有一雄一雌一對剛出生的兔子,它們在長到一個月大小時開始交配,在第二月結束時,雌兔子產下另外一對兔子,過了一個月後它們也開始繁殖,如此這般持續下去。每隻雌兔在開始繁殖時每個月都產下一對兔子,假定沒有兔子死亡,在一年後總共會有多少對兔子?函數
還有上樓梯的走法問題:有一段樓梯有10級臺階,規定每一步只能跨一級或兩級,要登上第10級臺階有幾種不一樣的走法?oop
先從字面上看:優化
我的認爲迭代是循環的一種,循環體代碼分爲固定循環體,和變化的循環體。spa
固定循環舉例:.net
for($i=0; $i < 8; $i++){ echo 'Welcome to NowaMagic'; }
實現迭代翻譯
$sum = 0; for($i = 1; $i <= 1000; $i++ ){ $sum = $sum + i; }
上面的迭代是常見的遞增式迭代。相似的還有遞減式迭代,遞乘式迭代。
迭代的好處:迭代減小了冗餘代碼,提升了代碼的利用率和動態性。
1. 遞歸算法與迭代算法的設計思路區別在於:函數或算法是否具有收斂性,當且僅當一個算法存在預期的收斂效果時,採用遞歸算法纔是可行的,不然,就不能使用遞歸算法。
固然,從理論上說,全部的遞歸函數均可以轉換爲迭代函數,反之亦然,然而代價一般都是比較高的。但從算法結構來講,遞歸聲明的結構並不總可以轉換爲迭代結構,緣由在於結構的引伸自己屬於遞歸的概念,用迭代的方法在設計初期根本沒法實現,這就像動多態的東西並不老是能夠用靜多態的方法實現同樣。這也是爲何在結構設計時,一般採用遞歸的方式而不是採用迭代的方式的緣由,一個極典型的例子相似於鏈表,使用遞歸定義及其簡單,但對於內存定義(數組方式)其定義及調用處理說明就變得很晦澀,尤爲是在遇到環鏈、圖、網格等問題時,使用迭代方式從描述到實現上都變得很不現實。
2. 遞歸實際上是方便了程序員難爲了機器。它只要獲得數學公式就能很方便的寫出程序。優勢就是易理解,容易編程。但遞歸是用棧機制實現的,每深刻一層,都要佔去一塊棧數據區域,對嵌套層數深的一些算法,遞歸會力不從心,空間上會之內存崩潰而了結,並且遞歸也帶來了大量的函數調用,這也有許多額外的時間開銷。因此在深度大時,它的時空性就很差了。
循環其缺點就是不容易理解,編寫複雜問題時困難。優勢是效率高。運行時間只因循環次數增長而增長,沒什麼額外開銷。空間上沒有什麼增長。
3. 局部變量佔用的內存是一次性的,也就是O(1)的空間複雜度,而對於遞歸(不考慮尾遞歸優化的狀況),每次函數調用都要壓棧,那麼空間複雜度是O(n),和遞歸次數呈線性關係。
4. 遞歸程序改用循環實現的話,通常都是要本身維護一個棧的,以便狀態的回溯。若是某個遞歸程序改用循環的時候根本就不須要維護棧,那其實這個遞歸程序這樣寫只是意義明顯一些,不必定要寫成遞歸形式。但不少遞歸程序就是爲了利用函數自身在系統棧上的auto變量記錄狀態,以便回溯。
原理上講,全部遞歸都是能夠消除的,代價就是可能本身要維護一個棧。並且我我的認爲,不少狀況下用遞歸仍是必要的,它每每能把複雜問題分解成更爲簡單的步驟,並且很能反映問題的本質。
遞歸其實就是利用系統堆棧,實現函數自身調用,或者是相互調用的過程。在通往邊界的過程當中,都會把單步地址保存下來,知道等出邊界,再按照先進後出的進行運算,這正如咱們裝木桶同樣,每一次都只能把東西方在最上面,而取得時候,先放進取的反而最後取出。遞歸的數據傳送也相似。可是遞歸不能無限的進行下去,必須在必定條件下中止自身調用,所以它的邊界值應是明確的。就向咱們裝木桶同樣,咱們不能老是無限制的往裏裝,必須在必定的時候把東西取出來。比較簡單的遞歸過程是階乘函數,你能夠去看一下。可是遞歸的運算方法,每每決定了它的效率很低,由於數據要不斷的進棧出棧。