演算法思想雜談 原創

2022-05-23 04:57:07 字數 3092 閱讀 8189

我接觸演算法設計已經5年了,從一開始零零散散,淺嘗輒止,到現在全面學習,深入**,學到了不少的優秀演算法,在這裡我想分享一下我這幾年來總結的學習方法。

首先我先把看過的演算法思想說一下,再介紹幾種最近出現的新思想。

顧名思義,貪心演算法總是作出在當前看來最好的選擇。也就是說貪心演算法並不從整體最優考慮,它所作出的選擇只是在某種意義上的區域性最優選擇。當然,希望貪心演算法得到的最終結果也是整體最優的。雖然貪心演算法不能對所有問題都得到整體最優解,但對許多問題它能產生整體最優解。如單源最短路經問題,最小生成樹問題等。在一些情況下,即使貪心演算法不能得到整體最優解,其最終結果卻是最優解的很好近似。在面臨選擇時,貪心演算法都作出對眼前來講最有利的選擇,不考慮對將來的不良影響,每個選擇一旦做出,不可更改,不允許回溯,根據不同的貪心策略,貪心演算法就不同,貪心解的質量也不同,所以貪心策略很重要。可以看出,此演算法思想很簡單,具有高效性,但不一定得出最優解。

當我們求解某些問題時,由於這些問題要處理的資料相當多,或求解過程相當複雜,使得直接求解法在時間上相當長,或者根本無法直接求出。對於這類問題,我們往往先把它分解成幾個子問題,找到求出這幾個子問題的解法後,再找到合適的方法,把它們組合成求整個問題的解法。如果這些子問題還較大,難以解決,可以再把它們分成幾個更小的子問題,以此類推,直至可以直接求出解為止。這就是分治策略的基本思想。

動態規劃演算法通常用於求解具有某種最優性質的問題。在這類問題中,可能會有許多可行解。每乙個解都對應於乙個值,我們希望找到具有最優值的解。動態規劃演算法與分治法類似,其基本思想也是將待求解問題分解成若干個子問題,先求解子問題,然後從這些子問題的解得到原問題的解。與分治法不同的是,適合於用動態規劃求解的問題,經分解得到子問題往往不是互相獨立的。若用分治法來解這類問題,則分解得到的子問題數目太多,有些子問題被重複計算了很多次。如果我們能夠儲存已解決的子問題的答案,而在需要時再找出已求得的答案,這樣就可以避免大量的重複計算,節省時間。我們可以用乙個表來記錄所有已解的子問題的答案。不管該子問題以後是否被用到,只要它被計算過,就將其結果填入表中。這就是動態規劃法的基本思路。

搜尋法包含窮舉搜尋,深度優先搜尋,廣度優先搜尋,回溯法,分支限界法,其實這些演算法的基礎就是窮舉搜尋,只是加上一定的原則來優化過程,就形成了後面的幾種演算法,回溯法就是在深度優先搜尋的基礎上允許回溯,分支限界法是在廣度優先搜尋基礎上允許剪枝,學習時主要學習思想,這些演算法名字不要太在意。

隨機化演算法,線性規劃問題,數論演算法等,這些演算法都是基於嚴格的數學理論,沒有很好的數學基礎看起來就有點難了。

① 遺傳演算法:從達爾文的生物演化論中得到啟發,借鑑自然選擇和進化的原理,模擬生物在自然界的進化過程所形成的一種優化求解方法,遺傳演算法從代表問題的可能潛在解集的乙個種群出發,乙個種群有一定數量的個體組成,每個個體實際上是染色體帶有特徵的實體,每一代根據個體的適應度大小挑選個體,並借助遺傳運算元進行交叉和變異,得到近似最優解。

② 模擬退火演算法:他的出發點是物理中固體的退火過程與一般組合優化之間的相似性,固態物質退火時,通常先加溫,使其中的粒子自由游動,然後逐漸降低溫度,粒子也逐漸形成低能態的晶格,最終形成最低能量的基態。所以他從某一較高初溫開始,伴隨溫度引數的不斷下降重複抽樣,最終得到全域性最優解,他是基於概率的。

③ 蟻群演算法:蟻群演算法是模擬自然界螞蟻覓食過程的一種分布式,啟發式群體智慧型演算法,用於求解複雜的組合優化問題,如tsp,jssp,gcp等問題。

演算法最初就是為了解決某一具體問題而想出來的一種解決方案,隨著對這一問題進行抽象,會得到一種解決這種型別相似問題的方案,這就是演算法,或者說演算法思想。並不是很複雜的解決方案才能稱演算法,其實解決每一問題的設計都是乙個演算法,只不過可能沒有對他們進行抽象,導致只能解決這一具體問題。

演算法並不像一些人想的那麼死板,也不像那麼複雜。並不是沒學過演算法分析設計就不會設計演算法,從上面我對演算法的解釋看出,任何人都能設計,有的人甚至比學過那門課的人設計的還好,究其原因,因為演算法實質上是一種解決問題的思想。學過《演算法分析與設計》的人知道,書裡面有很多優秀演算法,每乙個都不很簡單,大部分人可能簡單地認為「以後只要見到類似的問題,直接套現成演算法就行了」。事實上,那些演算法中蘊含的思想才是我們真正應該掌握的,並內化到自己的思想中。當我們遇到問題時,可能會有兩種解決方法:學過演算法分析設計的人可能會回想之前學過的演算法和問題,看哪個可以套的上;另一種沒學過的,應該就是不管三七二十一,先想出解決問題的原始方案,然後再對其優化。這兩種方法都行,可能大部分人用的是後一種方法,其實這些優秀演算法,在一開始也是這麼來的。如果將兩種方法結合,利用已內化的演算法思想找出原始方案,在對其優化,這才是最好的解決步驟。可以看出,這些演算法思想還是要學習的,他可以幫助盡快想出比較好的解決方案,如果不用這些思想,自己慢慢想,優化到最後,可能會發現,這不就是某種演算法思想嗎!所以我們要站在巨人的肩膀上。學習思想最重要的用處是,當遇到從沒見過的問題時,這時已經不能套用已有的模板,就只能厚積薄發,靠積累的演算法思想了,有可能會發現一種新思想!

程式=演算法+資料結構

其中演算法才是關鍵,資料結構和具體的程式語言只是工具,只有演算法思想是核心,是不變的。我們編寫的程式實質是解決某一問題的自動化實現方式,而當遇到一系列問題時,我們可以逐個解決,最終組合一起來解決總的問題,那麼怎麼解決某個具體問題就是關鍵,而解決這一問題的過程其實就是演算法,從這可以看出,程式從頭到尾都是在編寫演算法,這就是演算法重要的原因。優秀的演算法可以讓程式更加高效,健壯,能夠解決一類問題。這裡有乙個陷阱,演算法由於實質上還是為了解決問題,它受多種因素例如環境,理解力,程式架構等影響,所以只要他能很好的解決問題就可以了,不要一味的追求其所謂的「完美」。

演算法的學習最重要的是,一定要注重實踐,自己多想多實現,只有這樣才能把演算法思想內化。不是在課堂上聽聽課,做兩道課後習題就能掌握的。平時,遇到問題,可以先按照自己的想法或者邏輯,寫出初步解決方案,再對其優化。當然,也可以根據已有的類似演算法模擬,但是一定要自己想出來,不是按照書上的演算法套。對於學習這門課程,並不要求裡面的每乙個演算法都會寫出來,但解決問題的思想一定要掌握,具體來說,對於每個演算法或者問題,都要深入理解,理解他為什麼要這樣做,不這樣行不行,知道他每一步是怎麼走的,雖然我強調最重要掌握思想,但理解具體的演算法和這並不矛盾,只有具體的理解了,才能掌握思想,否則都是空話。只不過最後落下的就只有思想,無招勝有招。什麼揹包問題,旅行商問題,最短路徑....都只是具體問題而已。當然,如果這些具體演算法能記住那更好,但這不是必須的。有的演算法有數學理論基礎,比如數論演算法,這一類演算法主要靠數學建模,如果數學好,那就很簡單了,這一類思想實質就是數學理論。另外,做筆記是必要的,在把這些思想內化之前,要把看過的優秀演算法的過程描繪並記下來,並總結出思想,在某一天忘了,可以很快看懂。這就是積累!

設計思想與程式設計雜談(1)

計算機發展有六十年的歷史,從最初的二進位製碼到如今的超高階語言,使用越來越方便,越來越有時間處理關鍵業務,而不是深陷於如何實現。縱論各個時代的程式語言,就可以想象得出當時的設計理論。機器碼和組合語言時代,在設計軟體的時候,都不是以資料為中心的,基本上採用的都是 從上至下,逐步細化 的設計方法,關注點...

演算法程式設計雜談

1.並查集 陣列並查,高效的判斷資料是否在同一集合,套用 模板即可。遞迴呼叫find x 迴圈歸併merge a,b fd a b 2.揹包問題 分為0 1揹包,完全揹包,多重揹包 問題。使用動態規劃,簡介,功能強大,需要較多的時間去理解思考。也是電腦科學與程式設計神奇魅麗所在。計算轉移方程,推薦二...

演算法思想 滑動視窗思想

在解leetcode題的時候,遇到了幾個新的演算法思想,這個系列文章就把leetcode中的一些演算法思想做一些整理,包括老生常談的動態規劃,也包括我最新接觸的滑動視窗思想,並查集等,另外,遇到新的題目的時候也會在這裡做一些整理。起源 計算機網路協議 在介紹滑動視窗思想之前,首先介紹這個演算法思想的...