本文目錄
0 前言
1 遞迴
1.1 什麼是遞迴
1.2 為什麼要用遞迴
1.3 遞迴函式的格式
1.4 遞迴和迭代
1.4.1 遞迴
1.4.2 迭代
1.5 遞迴演算法的經典用例
2 回溯
2.1 什麼是回溯
2.2 回溯演算法的經典用例
遞迴和回溯不是乙個資料結構,但是它們是很經典很實用的經典演算法,使用遞迴和回溯可以更加簡潔高效的解決我們的問題。
任何呼叫自身的函式稱為遞迴。用遞迴方法求解問題,要點在於遞迴函式呼叫自身去解決乙個規模比原始問題小一些的問題。這個過程稱為遞迴步驟。遞迴步驟會導致更多的遞迴呼叫。因此,保證遞迴能夠終止是很重要的。每次函式都會用筆原問題規模更小的問題來呼叫自身。問題隨著規模不斷變小必須能最終收斂到基本情形。
在程式中,遞迴**通常比迭代**更加簡潔易懂。一般來說,在編譯或解釋時,迴圈會轉化為遞迴函式。當任務能夠被相似的子任務定義時,採用遞迴處理十分有效。例如,排序,搜尋和遍歷等問題往往有簡潔的遞迴解決方案。
遞迴函式在執行乙個任務時,需要呼叫函式自身來完成一些子任務。在某些時候,函式不需要繼續呼叫函式自身就可以完成當前子任務。函式不再遞迴的情況稱作基本情形。而函式呼叫自身來執行子任務的情況就稱作遞迴情形。遞迴的格式如下:
if(判斷是否為基本情形)else if(判斷是否為另一種基本情形)else
遞迴通過類似映象的方式來解決問題。當問題沒有明顯的答案是,遞迴方法通過簡化問題來解決它。但是,每次遞迴呼叫都會增加開銷(棧空間開銷)。遞迴和迭代對比描述如下:
(1)當到達基本情形時,遞迴終止;
(2)每次遞迴呼叫都需要額外的空間用於棧幀(記憶體)開銷;
(3)如果出現無窮遞迴,程式可能會耗盡記憶體,並出現棧溢位;
(4)某些問題採用遞迴方法更容易解決。
(1)當迴圈條件為假時,迭代終止;
(2)每次迭代不需要任何額外的空間開銷;
(3)由於沒有額外的空間開銷,所有若出現死迴圈,則程式會一直迴圈執行;
(4)採用迭代求解問題可能沒有遞迴解決方案那樣顯而易見。
常常需要用到遞迴來輔助解決問題有以下方面:
(1)斐波那契數列、階乘;
(2)歸併排序、快速排序;
(3)二分查詢;
(4)樹的遍歷和許多樹問題:中序遍歷、前序遍歷、後序遍歷;
(5)圖的遍歷:深度優先搜尋、廣度優先搜尋;
(6)動態規劃例子;
(7)分治演算法;
(8)漢諾塔;
(9)回溯演算法。
回溯是一種採用分治策略進行窮舉搜尋的方法。
(1)有時求解乙個問題的最好演算法是嘗試所有的可能性;
(2)這種方法通常很慢,但有標準工具能夠輔助該過程;
(3)工具:生成基本物件的演算法,例如二進位制串、排序、組合、一般字串等;
(4)通過剪枝回溯可以加速的窮舉搜尋。
回溯演算法經典用例有如下:
(1)二進位制串:產生所有的二進位制串;
(2)生成k進製串;
(3)揹包問題;
(4)廣義字串;
(5)哈密頓迴路;
(6)圖著色問題。
資料結構與演算法 遞迴和回溯
理論 遞迴函式在執行乙個任務時,需要呼叫函式自身來完成一些子任務。在某些時候,函式不需要繼續呼叫函式自身就可以完成當前子任務。函式不再遞迴的情況稱作基本情形 base case,也稱為基本情況 而函式呼叫自身來執行子任務的情況就稱作遞迴情形 recursive case 形式描述 舉例 理論 每次遞...
Java資料結構與演算法 遞迴和回溯
任何呼叫自身的函式成為遞迴。遞迴是從跟數學領域借鑑過來的一種有用的技術,遞迴 通常比迭代 更加簡潔易懂。以階乘喂例,其遞迴定義如下 n 1 n 0 n n n 1 n 0 複製 實現 public static void main string args static int fact int n ...
資料結構與演算法練習 回溯 遞迴
輸入乙個字串,按字典序列印出該字串中字元的所有排列。例如輸入字串abc,則列印出由字元a,b,c所能排列出來的所有字串abc,acb,bac,bca,cab和cba。結果請按字母順序輸出。輸入乙個字串,長度不超過9 可能有字元重複 字元只包括大小寫字母。i個字母的排列組合和i 1個字母的排列組合問題...