本篇是資料結構與演算法之美學習筆記
遞迴在電腦科學中指一種通過將重複問題分解為同列子問題來解決問題的方法。
遞迴是一種常見的演算法或者程式設計技巧。很多資料結構和演算法的編碼實現都會使用到遞迴,比附dfs深度搜尋,前中後序二叉樹遍歷等等。
遞迴需要滿足三個條件
1.乙個問題的解可以分成幾個解。
子問題就是資料規模更小的的問題
2.這個問題和分解之後的子問題,除了資料規模不同,解決思路是一樣的。
3.存在遞迴的終止條件
如果沒有終止條件就成了無限迴圈了。
如何寫乙個遞迴呢?最關鍵的兩部就是寫出遞推公式,和找到終止條件。
例子一:求階乘
intf(
int n)
例子二:假如有n個台階,每次可以跨乙個或者兩個台階,請問走著n個台階有多少種走法?
根據第一步的走法可以分成兩類:第一步走了乙個台階和第一步走了兩個台階。所以n個台階的走法就等於西安歐一階後n-1個台階的走法加上先走兩階後n-2個台階的走法。
intf(
int n)
寫遞迴**,關鍵就是找到如何將大問題分解為小問題的規律,並且基於此寫出遞推公式,然後在推敲終止條件,最後將遞推公式和終止條件翻譯成**。
遞迴**要警惕堆疊溢位
在實際開發中,寫遞迴**經常會遇到堆疊溢位的情況,後果非常嚴重。為什麼會造成堆疊溢位呢?怎麼可以防止堆疊溢位?
我們知道,函式的呼叫會使用棧來儲存臨時變數,每呼叫乙個函式,都會講臨時變數封裝成棧幀亞茹記憶體中,等函式執行完成返回時才出棧。系統或虛擬機器的棧控制項一般都不大。如果遞迴求解的資料很大,呼叫層次很深,一直壓入棧,就會有堆疊溢位的風險了。
我們可以通過在**中限制遞迴效用的最大深度的方式來解決這個問題,比如在遞迴深度超過1000之後就不往下遞迴了,直接返回錯誤
不過這種方法並不能完全解決問題,因為最大允許的遞迴深度跟當前的執行緒剩的棧的空間大小有關,事先無法計算,如果實時計算**過於複雜。所以如果深度太深,就不要用遞迴了。
遞迴**需警惕重複計算
比如上面的第二個例子加入n為6我們分解開的話
f(6)->f(5)->f(4)->f(3)->f(2)
f(6)->f(5)->f(4)->f(3)->f(1)
f(6)->f(5)->f(4)->f(2)
f(6)->f(5)->f(3)->f(2)
f(6)->f(5)->f(3)->f(1)
f(6)->f(4)->f(3)->f(2)
f(6)->f(4)->f(3)->f(1)
f(6)->f(4)->f(2)
從上面可以看到f(3)被計算了很多次。
為了避免重複計算,我們可以通過乙個資料結構(比如雜湊表)來儲存已經求結果的f(k)。當遞迴呼叫到f(k)的時候,先看一下是否求解過了,如果是直接在刪列表中取值返回。
例子二的**可以改為下面實現
public
intf
(int n)
int ret =
f(n-1)
+f(n-2);
hassovledlist.
put(n, ret)
;return ret;
}
遞迴除錯,對於比較淺的遞迴,可以使用單步追蹤的方法除錯,對於比較深的,可以通過列印日誌的方式來除錯。 資料結構之遞迴
資料結構與演算法遞迴 class solution def factorial self,n if n 1 return 1else return n factorial n 1 如果查詢的資料是有序的,二分查詢演算法比順序查詢演算法更高效 defbinary search nums,v nums....
資料結構之遞迴
程式呼叫自身的程式設計技巧稱為遞迴 recursion 遞迴做為一種演算法 在程式語言中廣泛應用。乙個過程或函函式在其定義或說明中有直接或間接呼叫自身的一種方法,它通常把乙個大型複雜的問題層層轉化為乙個與原問題相似的規模較小的問題來求解,遞迴策略只需少量的程式就可描述出解題過程所需要的多次重複計算,...
資料結構之遞迴
遞迴的四條基本準則 基準情形 必須總要有某些基準情形,它無需遞迴就能解出 不斷推進 對於那些需要遞迴求解的情形,每一次遞迴呼叫都必須使狀況朝向一種基準情形推進 設計法則 假設所有的遞迴呼叫都能執行 合成效益法則 在求解乙個問題的同一例項時,切勿在不同的遞迴呼叫中做重複性的工作。例 求整數的二進位制中...