一般情況下,只有在處理大量資料時才會借助於計算機,所以演算法設計中很重要的工作是把對資料的處理歸結成較為規範的可重複的「機械化操作」,然後交給計算機去完成。即將重複處理的大量資料的步驟抽象化成「迴圈」或「遞迴」的模式,設計出可以針對不同規模解決問題的演算法。
迴圈演算法設計中,乙個重要的工作就是從已經建立好的數學模型中,構造出「不變式」的「迴圈條件」,「迴圈體」。不變式主要是依靠變數或者陣列元素表示的,因為變數名或者陣列元素是『不變的』,而變數或者陣列元素中的資料是不斷變化的,從而資料處理是動態的、漸進的。
迴圈設計的要點:
(1)設計中要注意演算法的效率,盡可能使用層數少的迴圈來完成。
具體事例請參考:例項1
(2)自頂向下的設計方法:自頂向下的方法是從全域性走向區域性、從概略走向詳盡的設計方法,自上而下是系統分節和細化的過程。
具體事例請參考:例項2
(3)由具體到抽象設計迴圈結構:對於不太熟悉的問題,其數學模型或者「機械化操作步驟」不易抽象時,採用由具體到抽象的設計方法。
具體事例請參考:例項3
遞迴設計要點:
遞迴演算法的設計,就是把乙個大型複雜的問題層層轉化為乙個與原問題相似的規模較小的問題,在逐步求解小問題後,再返回(回溯)得到大問題的解。遞迴演算法只需要少量的步驟就可以描述出解題過程所需要的多次重複計算,大大地減少了演算法的**量。遞迴演算法的設計在於找出遞迴關係(方程)和遞迴終止(邊界)條件。遞迴關係就是使問題向邊界條件轉化的規則。遞迴關係必須能使問題越來越簡單,規模越來越小。遞迴邊界條件就是所描述問題最簡單的、可解的情況,它本身不再使用遞迴的定義。
因此,遞迴演算法解題通常又3個步驟:
(1)分析問題,尋找遞迴關係:找出大規模問題與小規模問題的關係,這樣通過遞迴使問題的規模逐漸變小。
(2)設定邊界,控制遞迴:找出停止條件,即演算法可解的最小規模問題。
(3)設計函式,確定引數:和其他演算法模組一樣設計函式體重的操作及相關引數。
具體事例請參考:漢諾塔問題
遞迴與迴圈的比較
遞迴也是一種實現「重複操作」的機制,它吧「較複雜」的操作依次地歸結為「較簡單」操作,一直歸結到「最簡單」的操作,能方便完成操作作為止。可以證明:每個迭代演算法原則上總可以轉換為與它等價的遞迴演算法;反之不然,即並不是每個遞迴演算法都可以轉換成與它等價的迴圈結構演算法。
具體事例請參考:
(1)遞迴確實可以使一些複雜的問題處理起來簡單明瞭,但是,就效率而言,遞迴演算法的實現往往要比迴圈結構的演算法耗費更多的時間和儲存空間。所以子啊具體實現時,方便的情況下應該把遞迴演算法轉化為等價的迴圈結構演算法,以提高演算法的時空效率。
具體事例請參考:從低位到高位輸出正整數 ;從高位到低位輸出正整數
(2)由於遞迴演算法的實現包括遞迴和回溯兩步,當問題需要『後進先出』的操作時,還是使用遞迴演算法更有效。如資料結構中的樹的前,中,後序遍歷,圖的dfs和bfs等,所以不僅僅只從效率上評價兩種控制重複操作機制的好壞。
具體事例請參考:用2的冪次方表示任何正整數
(3)遞迴是一種強有力的演算法設計工具。遞迴是一種比迴圈更強,更好用的實現「重複操作」的機制。因為遞迴不需要程式設計者自己構造「迴圈不變式」,而只找出遞迴關係和最小問題的解。遞迴子啊很多演算法策略中得以運用,如分治策略,動態規劃,圖的搜尋等。
具體事例請參考:n個自然數中取出r個數的排列組合
遞迴與非遞迴的比較:遞迴
非遞迴程式可讀性
容易困難
**量小
大時間消耗長短
空間消耗
大使用範圍廣窄
設計難度容易難
演算法基礎 遞迴(1)
遞迴的基本概念乙個函式呼叫其自身,就是遞迴。例1 求n 的遞迴函式 int factorial int n 遞迴的作用 替代多重迴圈 解決本來就是用遞迴型式定義的問題 將問題分解為規模更小的子問題進行求解 例2 漢諾塔問題 void hanoi int n,char src,char mid,cha...
資料結構與演算法 基礎演算法篇 遞迴
遞迴是一種非常高效 簡潔的編碼技巧,一種應用非常廣泛的演算法,比如dfs深度優先搜尋 前中後序二叉樹遍歷等都是使用遞迴。方法或函式呼叫自身的方式稱為遞迴呼叫,呼叫稱為遞,返回稱為歸。基本上,所有的遞迴問題都可以用遞推公式來表示,比如 f n f n 1 1 f n f n 1 f n 2 f n n...
遞迴和迴圈
從功能上來說,所有用遞迴實現的都可以用迴圈實現,只不過有時候遞迴實現方便一些,從效率上說,迴圈一般都是大於遞迴的。如果要處理的問題的深度不大,我認為遞迴和迭代的效率差不多。遞迴是消費棧空間,先遞推 壓棧 然後回歸 逐步釋放占用的棧 如果遞迴的深度比較大的話會很消耗記憶體,如果沒有終止條件會導致棧溢位...