程序員必需要知道的8種經常使用算法思想(轉)

知乎連接:https://zhuanlan.zhihu.com/p/56583442程序員

 

算法思想有不少,業界公認的經常使用算法思想有8種,分別是枚舉、遞推、遞歸、分治、貪心、試探法、動態迭代和模擬。固然8種只是一個大概的劃分,是一個「仁者見仁、智者見智」的問題。算法

枚舉算法思想

 

枚舉算法思想的最大特色是,在面對任何問題時它會去嘗試每一種解決方法。在進行概括推理時,若是逐個考察了某類事件的全部可能狀況,於是得出通常結論,那麼這個結論是可靠的,這種概括方法叫做枚舉法。編程

枚舉算法基礎函數

枚舉算法的思想是:將問題的全部可能的答案一一列舉,而後根據條件判斷此答案是否合適,保留合適的,丟棄不合適的。在C語言中,枚舉算法通常使用while循環實現。使用枚舉算法解題的基本思路以下。設計

① 肯定枚舉對象、枚舉範圍和斷定條件。3d

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

枚舉算法通常按照以下3個步驟進行。對象

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

② 判斷是不是真正解的方法。遞歸

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

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

 

 

1-1枚舉算法流程圖

 

遞推算法思想

 

與枚舉算法思想相比,遞推算法可以經過已知的某個條件,利用特定的關係得出中間推論,而後逐步遞推,直到獲得結果爲止。因而可知,遞推算法要比枚舉算法聰明,它不會嘗試每種可能的方案。

 

遞推算法基礎

遞推算法能夠不斷利用已有的信息推導出新的東西,在平常應用中有以下兩種遞推 算法。

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

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

遞歸算法思想

 

由於遞歸算法思想每每用函數的形式來體現,因此遞歸算法須要預先編寫功能函數。這些函數是獨立的功能,可以實現解決某個問題的具體功能,當須要時直接調用這個函數便可。

遞歸算法基礎

在計算機編程應用中,遞歸算法對解決大多數問題是十分有效的,它可以使算法的描述變得簡潔並且易於理解。遞歸算法有以下3個特色。

① 遞歸過程通常經過函數或子過程來實現。

② 遞歸算法在函數或子過程的內部,直接或者間接地調用本身的算法。

③ 遞歸算法其實是把問題轉化爲規模縮小了的同類問題的子問題,而後再遞歸調用函數或過程來表示問題的解。

在使用遞歸算法時,讀者應該注意以下4點。

① 遞歸是在過程或函數中調用自身的過程。

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

③ 遞歸算法一般顯得很簡潔,可是運行效率較低,因此通常不提倡用遞歸算法設計程序。

④ 在遞歸調用過程當中,系統用棧來存儲每一層的返回點和局部量。若是遞歸次數過多,則容易形成棧溢出,因此通常不提倡用遞歸算法設計程序。

分治算法思想

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

分治算法基礎

在編程過程當中,常常遇處處理數據至關多、求解過程比較複雜、直接求解法會比較耗時的問題。在求解這類問題時,能夠採用各個擊破的方法。

具體作法是:先把這個問題分解成幾個較小的子問題,找到求出這幾個子問題的解法後,再找到合適的方法,把它們組合成求整個大問題的解。若是這些子問題仍是比較大,還能夠繼續再把它們分紅幾個更小的子問題,以此類推,直至能夠直接求出解爲止。這就是分治算法的基本思想。

使用分治算法解題的通常步驟以下。

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

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

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

貪心算法思想

貪心算法也被稱爲貪婪算法,它在求解問題時總想用在當前看來是最好方法來實現。這種算法思想不從總體最優上考慮問題,僅僅是在某種意義上的局部最優求解。

雖然貪心算法並不能獲得全部問題的總體最優解,可是面對範圍至關普遍的許多問題時,能產生總體最優解或者是總體最優解的近似解。因而可知,貪心算法只是追求某個範圍內的最優,能夠稱之爲「溫柔的貪婪」。

貪心算法基礎

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

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

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

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

貪心算法的基本思路以下。

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

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

③ 對每一子問題求解,獲得子問題的局部最優解。

④ 把子問題的局部最優解合併成原來解問題的一個解。

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

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

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

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

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

試探算法思想

試探法也叫回溯法,試探法的處事方式比較委婉,它先暫時放棄關於問題規模大小的限制,並將問題的候選解按某種順序逐一進行枚舉和檢驗。當發現當前候選解不多是正確的解時,就選擇下一個候選解。

若是當前候選解除了不知足問題規模要求外可以知足全部其餘要求時,則繼續擴大當前候選解的規模,並繼續試探。若是當前候選解知足包括問題規模在內的全部要求時,該候選解就是問題的一個解。在試探算法中,放棄當前候選解,並繼續尋找下一個候選解的過程稱爲回溯。擴大當前候選解的規模,並繼續試探的過程稱爲向前試探。

試探法算法基礎

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

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

② 肯定易於搜索的解空間結構。

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

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

假設存在一個能夠用試探法求解的問題P,該問題表達爲:對於已知的由n元組(y1,y2,…,yn)組成的一個狀態空間E={(y1,y2,…,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元組(y1,y2,…,yi)知足D中僅涉及y1,y2,…,yj的全部約束,這意味着j(j<i)元組(y1,y2,…,yj)必定也知足D中僅涉及y1,y2,…,yj的全部約束,i=1,2,…,n。換句話說,只要存在0<=j<=n−1,使得(y 1,y 2,…,yj)違反D中僅涉及y1,y2,…,yj的約束之一,則以(y1,y2,…,yj)爲前綴的任何n元組(y1,y2,…,yj,yj+1,…,yn)必定也違反D中僅涉及y 1,y2,…,yi的一個約束,n>=i>;j。

所以,對於約束集D具備完備性的問題P,一旦檢測判定某個j元組(y1,y2,…,yj)違反D中僅涉及y1,y2,…,yj的一個約束,就能夠確定,以(y1,y2,…,yj)爲前綴的任何n元組(y1,y2,…,yj,yj+1,…,yn)都不會是問題P的解,於是就沒必要去搜索它們、檢測它們。試探法是針對這類問題而推出的,比枚舉算法的效率更高。

迭代算法

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

迭代算法基礎

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

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

(1)肯定迭代變量

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

(2)創建迭代關係式

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

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

在編寫迭代程序時,必須肯定在何時結束迭代過程,不能讓迭代過程無休止地重複執行下去。一般可分爲以下兩種狀況來控制迭代過程:

① 所需的迭代次數是個肯定的值,能夠計算出來,能夠構建一個固定次數的循環來實現對迭代過程的控制;

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

模擬算法思想

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

模擬算法的思路

模擬算法是一種基本的算法思想,可用於考查程序員的基本編程能力,其解決方法就是根據題目給出的規則對題目要求的相關過程進行編程模擬。在解決模擬類問題時,須要注意字符串處理、特殊狀況處理和對題目意思的理解。

在C語言中,一般使用函數srand()和rand()來生成隨機數。其中,函數srand()用於初始化隨機數發生器,而後使用函數rand()來生成隨機數。若是要使用上述兩個函數,則須要在源程序頭部包含time.h文件。在程序設計過程當中,可以使用隨機函數來模擬天然界中發生的不可預測狀況。在解題時,須要仔細分析題目給出的規則,要儘量地作到全面考慮全部可能出現的狀況,這是解模擬類問題的關鍵點之一。

相關文章
相關標籤/搜索