演算法工程師必須要知道的8種常用演算法思想

dicksonjyl560101發表於2019-02-08

https://blog.csdn.net/weixin_42137700/article/details/86777003


演算法思想有很多,業界公認的常用演算法思想有8種,分別是列舉、遞推、遞迴、分治、貪心、試探法、動態迭代和模擬。當然8種只是一個大概的劃分,是一個“仁者見仁、智者見智”的問題。

1.1 列舉演算法思想

知識點講解:光碟:視訊講解第2章列舉演算法思想.avi

列舉演算法思想的最大特點是,在面對任何問題時它會去嘗試每一種解決方法。在進行歸納推理時,如果逐個考察了某類事件的所有可能情況,因而得出一般結論,那麼這個結論是可靠的,這種歸納方法 叫作 列舉法。

1.1.1 列舉演算法基礎

列舉演算法的思想是:將問題的所有可能的答案一一列舉,然後根據條件判斷此答案是否合適,保留合適的,丟棄不合適的。在C語言中,列舉演算法一般使用while迴圈實現。使用列舉演算法解題的基本思路如下。

① 確定列舉物件、列舉範圍和判定條件。

② 逐一列舉可能的解,驗證每個解是否是問題的解。

列舉演算法一般按照如下3個步驟進行。

① 題解的可能範圍,不能遺漏任何一個真正解,也要避免有重複。

② 判斷是否是真正解的方法。

③ 使可能解的範圍降至最小,以便提高解決問題的效率。

列舉演算法的主要流程如圖1-1所示。


演算法工程師必須要知道的8種常用演算法思想

1-1列舉演算法流程圖


1.2 遞推演算法思想

知識點講解:光碟:視訊講解第2章遞推演算法思想.avi

與列舉演算法思想相比,遞推演算法能夠通過已知的某個條件,利用特定的關係得出中間推論,然後逐步遞推,直到得到結果為止。由此可見,遞推演算法要比列舉演算法聰明,它不會嘗試每種可能的方案。

1.2.1 遞推演算法基礎

遞推演算法可以不斷利用已有的資訊推匯出新的東西,在日常應用中有如下兩種遞推 演算法。

① 順推法:從已知條件出發,逐步推算出要解決問題的方法。例如斐波那契數列就可以通過順推法不斷遞推算出新的資料。

② 逆推法:從已知的結果出發,用迭代表示式逐步推算出問題開始的條件,即順推法的逆過程。

1.3 遞迴演算法思想

知識點講解:光碟:視訊講解第2章遞迴演算法思想.avi

因為遞迴演算法思想往往用函式的形式來體現,所以遞迴演算法需要預先編寫功能函式。這些函式是獨立的功能,能夠實現解決某個問題的具體功能,當需要時直接呼叫這個函式即可。在本節的內容中,將詳細講解遞迴演算法思想的基本知識。

1.3.1 遞迴演算法基礎

在計算機程式設計應用中,遞迴演算法對解決大多數問題是十分有效的,它能夠使演算法的描述變得簡潔而且易於理解。遞迴演算法有如下3個特點。

① 遞迴過程一般通過函式或子過程來實現。

② 遞迴演算法在函式或子過程的內部,直接或者間接地呼叫自己的演算法。

③ 遞迴演算法實際上是把問題轉化為規模縮小了的同類問題的子問題,然後再遞迴呼叫函式或過程來表示問題的解。

在使用遞迴演算法時,讀者應該注意如下4點。

① 遞迴是在過程或函式中呼叫自身的過程。

② 在使用遞迴策略時,必須有一個明確的遞迴結束條件,這稱為遞迴出口。

③ 遞迴演算法通常顯得很簡潔,但是執行效率較低,所以一般不提倡用遞迴演算法設計程式。

④ 在遞迴呼叫過程中,系統用棧來儲存每一層的返回點和區域性量。如果遞迴次數過多,則容易造成棧溢位,所以一般不提倡用遞迴演算法設計程式。

1.4 分治演算法思想

知識點講解:光碟:視訊講解第2章分治演算法思想.avi

在本節將要講解的分治演算法也採取了各個擊破的方法,將一個規模為 N 的問題分解為 K 個規模較小的子問題,這些子問題相互獨立且與原問題性質相同。只要求出子問題的解,就可得到原問題的解。

1.4.1 分治演算法基礎

在程式設計過程中,經常遇到處理資料相當多、求解過程比較複雜、直接求解法會比較耗時的問題。在求解這類問題時,可以採用各個擊破的方法。具體做法是:先把這個問題分解成幾個較小的子問題,找到求出這幾個子問題的解法後,再找到合適的方法,把它們組合成求整個大問題的解。如果這些子問題還是比較大,還可以繼續再把它們分成幾個更小的子問題,以此類推,直至可以直接求出解為止。這就是分治演算法的基本思想。

使用分治演算法解題的一般步驟如下。

① 分解,將要解決的問題劃分成若干個規模較小的同類問題。

② 求解,當子問題劃分得足夠小時,用較簡單的方法解決。

③ 合併,按原問題的要求,將子問題的解逐層合併構成原問題的解。

1.5 貪心演算法思想

知識點講解:光碟:視訊講解第2章貪心演算法思想.avi

本節所要講解的貪心演算法也被稱為貪婪演算法,它在求解問題時總想用在當前看來是最好方法來實現。這種演算法思想不從整體最優上考慮問題,僅僅是在某種意義上的區域性最優求解。雖然貪心演算法並不能得到所有問題的整體最優解,但是面對範圍相當廣泛的許多問題時,能產生整體最優解或者是整體最優解的近似解。由此可見,貪心演算法只是追求某個範圍內的最優,可以稱之為“溫柔的貪婪”。

1.5.1 貪心演算法基礎

貪心演算法從問題的某一個初始解出發,逐步逼近給定的目標,以便儘快求出更好的解。當達到演算法中的某一步不能再繼續前進時,就停止演算法,給出一個近似解。由貪心演算法的特點和思路可看出,貪心演算法存在以下3個問題。

① 不能保證最後的解是最優的。

② 不能用來求最大或最小解問題。

③ 只能求滿足某些約束條件的可行解的範圍。

貪心演算法的基本思路如下。

① 建立數學模型來描述問題。

② 把求解的問題分成若干個子問題。

③ 對每一子問題求解,得到子問題的區域性最優解。

④ 把子問題的區域性最優解合併成原來解問題的一個解。

實現該演算法的基本過程如下。

(1)從問題的某一初始解出發。

(2)while能向給定總目標前進一步。

(3)求出可行解的一個解元素。

(4)由所有解元素組合成問題的一個可行解。

1.6 試探法演算法思想

試探法也叫回溯法,試探法的處事方式比較委婉,它先暫時放棄關於問題規模大小的限制,並將問題的候選解按某種順序逐一進行列舉和檢驗。當發現當前候選解不可能是正確的解時,就選擇下一個候選解。如果當前候選解除了不滿足問題規模要求外能夠滿足所有其他要求時,則繼續擴大當前候選解的規模,並繼續試探。如果當前候選解滿足包括問題規模在內的所有要求時,該候選解就是問題的一個解。在試探演算法中,放棄當前候選解,並繼續尋找下一個候選解的過程稱為回溯。擴大當前候選解的規模,並繼續試探的過程稱為向前試探。

1.6.1 試探法演算法基礎

使用試探演算法解題的基本步驟如下所示。

① 針對所給問題,定義問題的解空間。

② 確定易於搜尋的解空間結構。

③ 以深度優先方式搜尋解空間,並在搜尋過程中用剪枝函式避免無效搜尋。

試探法為了求得問題的正確解,會先委婉地試探某一種可能的情況。在進行試探的過程中,一旦發現原來選擇的假設情況是不正確的,立即會自覺地退回一步重新選擇,然後繼續向前試探,如此這般反覆進行,直至得到解或證明無解時才死心。

假設存在一個可以用試探法求解的問題P,該問題表達為:對於已知的由 n 元組( y 1, y 2,…, yn )組成的一個狀態空間 E ={( y 1, y 2,…, yn )∣ yi Si i =1,2,…, n },給定關於 n 元組中的一個分量的一個約束集 D ,要求 E 中滿足 D 的全部約束條件的所有 n 元組。其中, Si 是分量 yi 的定義域,且| Si |有限, i =1,2,…, n E 中滿足 D 的全部約束條件的任一 n 元組為問題P的一個解。

解問題P的最簡單方法是使用列舉法,即對 E 中的所有 n 元組逐一檢測其是否滿足 D 的全部約束,如果滿足,則為問題P的一個解。但是這種方法的計算量非常大。

對於現實中的許多問題,所給定的約束集 D 具有完備性,即 i 元組( y 1, y 2,…, yi )滿足 D 中僅涉及 y 1, y 2,…, yj 的所有約束,這意味著 j j < i )元組( y 1, y 2,…, yj )一定也滿足 D 中僅涉及 y 1, y 2,…, yj 的所有約束, i =1,2,…, n 。換句話說,只要存在0<=j<= n −1,使得( y  1, y  2,…, yj )違反 D 中僅涉及 y 1, y 2,…, yj 的約束之一,則以( y 1, y 2,…, yj )為字首的任何 n 元組( y 1, y 2,…, yj yj+ 1,…, yn )一定也違反 D 中僅涉及 y  1, y  2,…, yi 的一個約束, n>=i >; j 。因此,對於約束集 D 具有完備性的問題P,一旦檢測斷定某個 j 元組( y 1, y 2,…, yj )違反 D 中僅涉及 y 1, y 2,…, yj 的一個約束,就可以肯定,以( y 1, y 2,…, yj )為字首的任何 n 元組( y 1, y 2,…, yj yj+ 1,…, yn )都不會是問題P的解,因而就不必去搜尋它們、檢測它們。試探法是針對這類問題而推出的,比列舉演算法的效率更高。

1.7 迭代演算法

迭代法也稱輾轉法,是一種不斷用變數的舊值遞推新值的過程,在解決問題時總是重複利用一種方法。與迭代法相對應的是直接法(或者稱為一次解法),即一次性解決問題。迭代法又分為精確迭代和近似迭代。“二分法”和“牛頓迭代法”屬於近似迭代法,功能都比較類似。

1.7.1 迭代演算法基礎

迭代演算法是用計算機解決問題的一種基本方法。它利用計算機運算速度快、適合做重複性操作的特點,讓計算機對一組指令(或一定步驟)進行重複執行,在每次執行這組指令(或這些步驟)時,都從變數的原值推出它的一個新值。

在使用迭代演算法解決問題時,需要做好如下3個方面的工作。

(1)確定迭代變數

在可以使用迭代演算法解決的問題中,至少存在一個迭代變數,即直接或間接地不斷由舊值遞推出新值的變數。

(2)建立迭代關係式

迭代關係式是指如何從變數的前一個值推出其下一個值的公式或關係。通常可以使用遞推或倒推的方法來建立迭代關係式,迭代關係式的建立是解決迭代問題的關鍵。

(3)對迭代過程進行控制

在編寫迭代程式時,必須確定在什麼時候結束迭代過程,不能讓迭代過程無休止地重複執行下去。通常可分為如下兩種情況來控制迭代過程:

① 所需的迭代次數是個確定的值,可以計算出來,可以構建一個固定次數的迴圈來實現對迭代過程的控制;

② 所需的迭代次數無法確定,需要進一步分析出用來結束迭代過程的條件。

1.8 模擬演算法思想

模擬是對真實事物或者過程的虛擬。在程式設計時為了實現某個功能,可以用語言來模擬那個功能,模擬成功也就相應地表示程式設計成功。

1.8.1 模擬演算法的思路

模擬演算法是一種基本的演算法思想,可用於考查程式設計師的基本程式設計能力,其解決方法就是根據題目給出的規則對題目要求的相關過程進行程式設計模擬。在解決模擬類問題時,需要注意字串處理、特殊情況處理和對題目意思的理解。在C語言中,通常使用函式srand()和rand()來生成隨機數。其中,函式srand()用於初始化隨機數發生器,然後使用函式rand()來生成隨機數。如果要使用上述兩個函式,則需要在源程式頭部包含time.h檔案。在程式設計過程中,可使用隨機函式來模擬自然界中發生的不可預測情況。在解題時,需要仔細分析題目給出的規則,要儘可能地做到全面考慮所有可能出現的情況,這是解模擬類問題的關鍵點之一。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29829936/viewspace-2600313/,如需轉載,請註明出處,否則將追究法律責任。

相關文章