本節是《Java數據結構及算法實戰》系列的第5節,主要介紹分析算法和數據結構的重要工具——漸近記法。
在前一節,我們介紹了程序的性能,也介紹了評估性能的方式。那麼,我們是否就能測算出算法需要運行的時間呢?
1.3.1 大O標記法
直接回答上述問題並非易事,原因在於,即使是同一算法,針對不同的輸入運行的時間並不相同。以排序問題爲例,輸入序列的規模、組成和次序都不是確定的,這些因素都會影響到排序算法的運行時間。在所有這些因素中,輸入的規模是最重要的一個。假設我們要對學生按照成績排序,那麼顯然,當學生的規模很少時(比如50個)所耗費的排序時間,肯定是要比當學生的規模很大時(比如50萬個)所耗費的排序時間短。
因此,在實際分析算法的時間複雜度時,通常只考慮輸入規模這一主要因素。如果將某一算法爲了處理規模爲n的問題所需的時間記作T(n),那麼隨着問題規模n的增長,運行時間T(n)我們將稱之爲算法的時間複雜度。
由於小規模的問題所需的處理時間相對更少,不同算法在效率方面的差異並不明顯,而只有在處理大規模的問題時,這方面的差異才有質的區別。因此,在評價算法的運行時間時,我們往往可以忽略其在處理小規模問題時的性能,轉而關注其在處理足夠大規模問題時的性能,即所謂的漸進複雜度(Asmpototic Complexity)。
另外,通常我們也不需要知道T(n)的確切大小,而只需要對其上界作出估計。比如說,如果存在正常數a、N和一個函數f(n),使得對於任何n > N
,都有
T(n) < a × f(n)
我們就可以認爲在n足夠大之後,f(n)給出了T(n)的一個上界。對於這種情況,我們記之爲
T(n) = O(f(n))
這裏的O稱作“大O記號(Big-O notation)”,是希臘字母omicron的大寫形式。從上述例子可以看出,大O記號實質上是對算法執行效率的一種保守估計⎯⎯對於規模爲n的任意輸入,算法的運行時間都不會超過O(f(n))。換言之,大O記號是對算法執行效率最差情況的估算。
大O記號是漸進記法的一種。漸進記法一直就是人們用於分析算法和數據結構的重要工具。其核心思想是:提供一種資源表示形式,主要用於分析某項功能在應對一定規模參數時需要的資源(通常是時間,有時候也會是內存)。常用的漸進記法還包括大Θ記號、大Ω記號。
1.3.2 大Ω標記法
如果存在正常數a、N和一個函數g(n),使得對於任何n>N,都有
T(n) > a × g(n)
我們就可以認爲在n足夠大之後,g(n)給出了T(n)的一個下界。對於這種情況,我們記之爲
T(n) = Ω(g(n))
這裏的Ω稱作“大Ω記號(Big-Ω notation)”,是希臘字母omega的大寫形式。大Ω記號與大O記號正好相反,它是對算法執行效率的一種樂觀估計⎯⎯對於規模爲n的任意輸入,算法的運行時間都不會低於Ω(g(n))。換言之,大O記號是對算法執行效率最好情況的估算。
1.3.3 大Θ標記法
如果存在正常數a<b
、N和一個函數h(n),使得對於任何n > N
,都有
a × h(n) < T(n) < b × h(n)
我們就可以認爲在n足夠大之後,h(n)給出了T(n)的一個確界。對於這種情況,我們記之爲
T(n) = Θ(h(n))
這裏的Θ稱作“大Θ記號(Big-Θ notation)”,是希臘字母theta的大寫形式。大Θ記號是對算法執行效率的一種準確估計⎯⎯對於規模爲n的任意輸入,算法的運行時間都與Θ(h(n))同階。
1.3.4 漸近記法總結
總結而言,漸近記法的含義如下表1-2所示。
表1-2 漸近記法含義
符號 | 含義 |
---|---|
O | 漸進小於或等於 |
Ω | 漸進大於或等於 |
Θ | 漸進等於 |
在上面度量算法複雜度的三種記號中,大O記號是最基本的,也是最常用到的。本書後續的算法複雜度也主要採用按照大O記號來表示。
參考引用
- 原本同步至:https://waylau.com/asymptotic-notation/
- 本系列歸檔至《Java數據結構及算法實戰》:https://github.com/waylau/java-data-structures-and-algorithms-in-action
- 《數據結構和算法基礎(Java語言實現)》:https://item.jd.com/13014179.html