遞歸&迭代&回溯&遞推&樹形遞歸&線性遞歸&尾遞歸概念彙總
引用文檔
https://www.jianshu.com/p/32bcc45efd32 遞歸與迭代的區別
知識儲備
在閱讀文章前需要查詢:
-
遞歸的定義
-
回溯的定義
-
迭代的定義
-
遞推的定義
-
樹形遞歸的定義
-
線性遞歸的定義
-
尾遞歸的定義
-
線性迭代的定義
筆記
-
遞歸:在數學上的理解,就是函數自己調用自己
-
迭代;迭代就是將別人的輸出作爲自己的輸入,得到最終的結果。從函數表現形式,就是自己調用別人。這個別人可以是自己。
-
遞歸是迭代的特殊形式。這個不難理解。
-
樹形遞歸,就是指遞歸函數的時間複雜度是指數級別。比如,自己調用自己兩次以上。
-
線性遞歸,就是指遞歸函數的時間複雜度是線性級別。比如,自己調用自己一次以上。
-
循環的3要素:循環終止條件,循環體,循環變量
-
遞歸分爲兩個過程,遞推和迴歸。遞推則是把複雜問題逐步分解爲最簡單的問題,迴歸就是把最簡單的問題完成後逐漸回溯到最原先的複雜問題。
-
回溯是一種算法思想,就是指當前算法進行下去以無意義時,回退上一步重新尋找新的解題思路。類似孫子兵法的三十六計走回上策。
-
遞歸的第一階段,遞進在計算機看來就是一個不停建立函數調用棧的過程。
-
遞歸的第二階段,迴歸的過程其實本質上就是一個迭代的過程。我們可以看待函數棧頂部的函數返回值回作爲函數棧中下- - 一個函數的輸入值。整個過程會把原先遞進過程建立的函數棧不停的退棧,直到迴歸最初建立的函數(函數棧的棧底函數)。
-
尾遞歸,是指,如果一個函數中所有遞歸形式的調用都出現在函數的末尾,我們稱這個遞歸函數是尾遞歸的。即,遞歸調用後返回的結果直接return;
-
尾遞歸,不會消耗棧空間,所以尾遞歸時間與空間複雜度和迭代的性能一樣。
-
下面是使用線性遞歸和尾遞歸分別求解階乘:
線性遞歸:
long Rescuvie(long n) {
return (n == 1) ? 1 : n * Rescuvie(n - 1);
}
尾遞歸:
long TailRescuvie(long n, long a) {
return (n == 1) ? a : TailRescuvie(n - 1, a * n);
}
long TailRescuvie(long n) {//封裝用的
return (n == 0) ? 1 : TailRescuvie(n, 1);
}
當n = 5時
對於線性遞歸, 他的遞歸過程如下:
Rescuvie(5)
{5 * Rescuvie(4)}
{5 * {4 * Rescuvie(3)}}
{5 * {4 * {3 * Rescuvie(2)}}}
{5 * {4 * {3 * {2 * Rescuvie(1)}}}}
{5 * {4 * {3 * {2 * 1}}}}
{5 * {4 * {3 * 2}}}
{5 * {4 * 6}}
{5 * 24}
120
對於尾遞歸, 他的遞歸過程如下:
TailRescuvie(5)
TailRescuvie(5, 1)
TailRescuvie(4, 5)
TailRescuvie(3, 20)
TailRescuvie(2, 60)
TailRescuvie(1, 120)
120
-
迭代算法可以轉化爲尾遞歸。尾遞歸算法也可以轉化爲遞歸算法。編譯器就是這麼幹的,編譯器經常會爲了減少函數開銷,把尾遞歸算法轉化爲迭代算法。而樹形遞歸和線性遞歸就無法做到這一點。尾遞歸也叫線性迭代。
-
從時間複雜度來劃分,可以分爲樹形遞歸和線性迭代.
尾遞歸也是一種特殊的線性遞歸,特殊在於他直接把遞歸函數的返回值直接return, 而一般的線性遞歸則需要把返回值帶入表達式運算後再return。
總結
-
突然我有一個習慣,不喜歡用代碼表示一些計算機概念,因爲代碼大多是計算機思維習慣。而人思考問題的時候大多是面向對象化的,甚至更加靈活,不應該侷限於計算機的思維。
-
爲什麼我不用思維導圖,思維導圖用於歸納知識,方便於信息閱讀和思維引導。而我做筆記的目的是爲了便於我記憶和自我檢索。我認爲,記憶是零散的,那麼就不應該強行對起結構化,避免注意力和關注點落在知識管理。零散的知識結構有利於使我更加專注知識的內容本身,而不是知識的結構管理。
-
零散的知識點方便我檢索。所以我故意弱化知識的歸納(除非有必要)。