- 程序員必會的40種算法
- (加)伊姆蘭·艾哈邁德
- 2727字
- 2021-09-27 16:59:59
4.1 算法設(shè)計基本概念
根據(jù)《美國傳統(tǒng)詞典》(American Heritage Dictionary),算法的定義如下:
“算法是由無歧義指令構(gòu)成的有限集合,它在給定的一組初始條件下按預(yù)定順序執(zhí)行,直到滿足給定的可識別的結(jié)束條件以實現(xiàn)某種目的。”
設(shè)計算法就是要給出這個“由無歧義指令構(gòu)成的有限集合”,以最有效的方式“實現(xiàn)某種目標(biāo)”。為復(fù)雜的實際問題設(shè)計算法是一項煩瑣的任務(wù)。要構(gòu)想得到一個好的設(shè)計,需要先充分了解待求解問題。我們首先要弄清楚需要做什么(即了解需求),然后再研究如何做(即設(shè)計算法)。理解問題包括找出待求解問題的功能性需求和非功能性需求,讓我們看看這些需求分別是什么:
- 功能性需求正式規(guī)定了待求解問題的輸入和輸出接口,以及與之相關(guān)的功能,幫助我們理解數(shù)據(jù)處理、數(shù)據(jù)操作,以及生成結(jié)果所需要執(zhí)行的計算。
- 非功能性需求設(shè)定了對算法的性能和安全性方面的預(yù)期。
需要注意的是,設(shè)計算法就是要在給定的環(huán)境下以最佳方式同時滿足功能性需求和非功能性需求,并且還要考慮到用于運行所設(shè)計算法的資源集。
為了得到一個能夠滿足功能性需求和非功能性需求的算法,我們的設(shè)計應(yīng)該考慮以下三個關(guān)注點(正如第一章所講):
- 第一點:所設(shè)計算法是否能產(chǎn)生我們預(yù)期的結(jié)果?
- 第二點:所設(shè)計算法是獲取預(yù)期結(jié)果的最佳方法嗎?
- 第三點:所設(shè)計算法在更大的數(shù)據(jù)集上表現(xiàn)怎么樣?
我們逐一討論這些問題。
4.1.1 第一點——所設(shè)計算法是否能產(chǎn)生預(yù)期的結(jié)果
算法是實際問題的數(shù)學(xué)求解方案,一個有效的算法應(yīng)該能夠產(chǎn)生準(zhǔn)確的結(jié)果。如何驗證算法的正確性,這不應(yīng)該是事后才需要的想法,而應(yīng)該是在算法的設(shè)計中就已經(jīng)考慮到了。在制定驗證算法的策略之前,我們需要考慮以下兩個方面:
- 定義真實值:為了驗證算法,對于給定的一組輸入,我們需要已知的正確結(jié)果。這些已知的正確結(jié)果在待求解問題中稱為真實值。真實值是很重要的,因為當(dāng)我們不斷地改進我們的算法,以獲得更好的求解方案時,它可以作為參考。
- 選擇度量標(biāo)準(zhǔn):我們還需要考慮如何量化運行結(jié)果與真實值之間的差距。選擇合適的度量標(biāo)準(zhǔn)將有助于我們準(zhǔn)確地量化算法的質(zhì)量。
例如,對于機器學(xué)習(xí)算法,我們可以將已標(biāo)記的現(xiàn)有數(shù)據(jù)用作真實值,可以選擇一個或多個度量標(biāo)準(zhǔn)(例如準(zhǔn)確率、召回率或精度)來量化與真實值之間的差距。需要注意的是,在某些用例中,正確的輸出不是一個單一的值,而是被定義為一組給定的范圍。在設(shè)計和開發(fā)算法的過程中,我們的目標(biāo)是反復(fù)改進算法,直到其運行結(jié)果位于需求所明確的范圍之內(nèi)。
4.1.2 第二點——所設(shè)計算法是否是獲取結(jié)果的最佳方法
第二個關(guān)注點是找到以下問題的答案:
所設(shè)計算法是最佳求解方案嗎?我們是否能夠證明該問題不存在更好的求解方案?
乍一看,這個問題似乎很容易回答。然而,對于某一類算法,研究人員花了幾十年的時間來驗證由某個算法產(chǎn)生的特定解是否也是最佳解,以及是否不存在可以給出更好結(jié)果的其他求解方案,但都沒有成功。所以,我們首先要了解問題、問題的需求以及運行算法的資源,這一點非常重要。我們需要確認(rèn)以下說法:
我們是否應(yīng)該以找到該問題的最優(yōu)解為目標(biāo)?尋找和驗證最優(yōu)解是非常耗時且復(fù)雜的,所以基于啟發(fā)式方法的可行方案是我們最好的選擇。
因此,理解問題及其復(fù)雜性很重要,它可以幫助我們估算對資源的需求。
在開始深入討論之前,我們先在這里定義幾個術(shù)語:
- 多項式算法(polynomial algorithm):如果算法的時間復(fù)雜度為O(nk),則我們將其稱為多項式算法,其中k為常數(shù)。
- 可行解(certificate):迭代結(jié)束時產(chǎn)生的一個候選解稱為可行解。隨著我們在解決特定問題上的不斷迭代,我們通常會產(chǎn)生一系列的可行解。如果解收斂,則每一個生成的可行解都會比前一個更好。在某些時候,當(dāng)我們的可行解滿足需求時,我們會選擇該可行解作為最終的解。
第1章介紹了大O記號,用以分析算法的時間復(fù)雜度。在分析時間復(fù)雜度的背景下,我們考慮以下不同的時間區(qū)間:
- 一個算法產(chǎn)生一個解(即可行解)所需要的時間tr。
- 驗證給出的解(可行解)所需的時間ts。
刻畫問題復(fù)雜度
多年來,學(xué)術(shù)界根據(jù)問題的復(fù)雜度將問題分為不同的類。在我們嘗試設(shè)計問題的求解方案之前,先嘗試確定它屬于哪一類問題是有意義的。一般來說,存在三種類型的問題:
- 類型1:肯定存在求解該問題的多項式算法。
- 類型2:可以證明這類問題無法用多項式算法求解。
- 類型3:無法找到求解該問題的多項式算法,也無法證明不可能找到該問題的多項式求解方案。
我們來看看各類問題:
- 非確定性多項式問題(NP):一個問題要成為NP問題,必須滿足以下條件:
- 肯定存在多項式算法用于驗證候選解(可行解)是否最優(yōu)。
- 多項式問題(P):這類問題可以視為NP問題的子集。除滿足NP問題的條件以外,P問題還需要滿足如下額外的條件:
- 肯定存在至少一種多項式算法來求解它們。
圖4-1展示了P問題和NP問題之間的關(guān)系。

圖 4-1
如果一個問題是NP問題,那么它也是P問題嗎?這是計算機科學(xué)領(lǐng)域中尚未解決的最大問題之一。它是由克萊數(shù)學(xué)研究所(Clay Mathematics Institute)評選的千禧年大獎難題(Millennium Prize Problems),并已宣布為這個問題的解決提供100萬美元的獎金,因為它將對人工智能、密碼學(xué)和理論計算機科學(xué)等領(lǐng)域產(chǎn)生重大影響:

下面繼續(xù)列出各類問題:
- NP完全問題:NP完全類包含了所有NP問題中最難的問題。一個NP完全問題需要滿足以下兩個條件:
- 沒有已知的多項式算法來生成可行解。
- 有已知的多項式算法來驗證提出的可行解是否最優(yōu)。
- NP難問題:NP難類包含的問題至少與NP類中的任何問題一樣難,但是這些問題本身并不需要屬于NP類。
現(xiàn)在,我們繪制一張圖(圖4-2)來說明各類問題之間的關(guān)系。

圖 4-2
注意,P=NP的正確性仍有待學(xué)術(shù)界證明。盡管這尚未得到證實,但很有可能P≠NP。在此種情況下,不存在求解NP完全問題的多項式求解方案。請注意,圖4-2是基于這個假設(shè)所畫的。
4.1.3 第三點——所設(shè)計算法在更大的數(shù)據(jù)集上表現(xiàn)如何
算法以規(guī)定的方式處理數(shù)據(jù)以產(chǎn)生結(jié)果。一般來說,隨著數(shù)據(jù)規(guī)模的增加,處理數(shù)據(jù)和計算所需結(jié)果的時間越來越長。術(shù)語大數(shù)據(jù)有時用于粗略地標(biāo)識由于數(shù)據(jù)的體積、多樣性和速度太大而預(yù)計對所使用的基礎(chǔ)結(jié)構(gòu)和算法構(gòu)成挑戰(zhàn)的數(shù)據(jù)集。一個設(shè)計良好的算法應(yīng)該是可擴展的,這意味著,它應(yīng)該盡可能高效地運行,利用可用的資源在合理時間內(nèi)產(chǎn)生正確的結(jié)果。在處理大數(shù)據(jù)時,算法的設(shè)計變得更加重要。為了量化算法的可擴展性,我們需要注意以下兩個方面的問題:
- 隨著輸入數(shù)據(jù)的增加,資源需求增加:對此進行的估計稱為空間復(fù)雜度分析。
- 隨著輸入數(shù)據(jù)的增加,運行時間增加:對此進行的估計稱為時間復(fù)雜度分析。
請注意,我們正生活在一個被定義為數(shù)據(jù)爆炸的時代。“大數(shù)據(jù)”一詞已經(jīng)成為主流,因為它抓住了現(xiàn)代算法通常需要處理的數(shù)據(jù)的規(guī)模和復(fù)雜性。
在開發(fā)和測試階段,許多算法僅使用少量的數(shù)據(jù)樣本。在設(shè)計算法時,研究算法的可擴展性是很重要的。特別是隨著數(shù)據(jù)集規(guī)模的增加,仔細(xì)分析(即測試或預(yù)測)算法性能的變化非常重要。
- Java范例大全
- 造個小程序:與微信一起干件正經(jīng)事兒
- Rust實戰(zhàn)
- Mastering Concurrency in Go
- FFmpeg入門詳解:音視頻流媒體播放器原理及應(yīng)用
- Linux網(wǎng)絡(luò)程序設(shè)計:基于龍芯平臺
- C#程序設(shè)計教程(第3版)
- Python3.5從零開始學(xué)
- OpenCV 3計算機視覺:Python語言實現(xiàn)(原書第2版)
- Hacking Android
- Qt 4開發(fā)實踐
- Learning Unreal Engine Game Development
- Mastering Embedded Linux Programming
- Android嵌入式系統(tǒng)程序開發(fā)(基于Cortex-A8)
- Unity 5 Game Optimization