複雜度分析

爲什麼要學習複雜度分析?

我們用開發工具將代碼跑一遍,通過統計和監控就能得到算法執行的時間和佔用的內存,爲什麼還要做算法的時間和空間複雜度分析?這種統計複雜度的方法我們稱爲"事後統計法 ",這種統計方法有如下侷限性:

  • 測試結果依賴測試環境
  • 測試結果受數據估摸影響很大

所以我們需要一個不需要具體數據和環境就能粗略估算算法執行效率的方法。

大O複雜度表示法

複雜度分析包括:

  • 時間複雜度分析
  • 空間複雜度分析
時間複雜度

我們假設沒句代碼執行的時間都是一個unit_time,因此所有代碼的執行時間T(n)與每行代碼的執行次數n成正比,把這個規律總結成一個公式:


這就是大O時間複雜度表示法:

  • T(n)表示代碼執行的時間
  • n表示數據規模的大小
  • f(n)表示每行代碼執行的次數總和
  • O表示代碼的執行時間T(n)與f(n)成正比

大O時間複雜度表示代碼執行時間隨數據規模的增長的變化趨勢,也叫漸進時間複雜度,簡稱時間複雜度。當n很大時,比如1000000,公式中的低階、常量、係數並不左右增長的趨勢可以忽略。例如T(n) = O(n+1)或T(n) = O(n²+2n+1),用大O表示法可以記爲T(n) = O(n)、T(n) = O(n²)。

時間複雜度分析

時間複雜度分析的技巧

  • 只關注循環執行次數最多的一段代碼
    大O表示的是一種變化趨勢,所以我們只需要關注最大階的量級就可以了。例如一個函數,有一個for循環執行n次,其餘代碼均只執行一次,那麼這個函數的時間複雜度就O(n);一個函數有一個for循環執行n次,還有一個for循環執行n²次,那這個函數的時間複雜度就是O(n²)。

  • 加法法則
    兩個函數的時間複雜度相加,總的複雜度等於量級最大的那段代碼的複雜度,原因同上一個技巧的解鎖。這裏要注意一點,如果某個函數裏面for循環循環執行10000次,而另一個函數循環執行n次,那這兩個函數相加後總的複雜度爲O(n),因爲大O表示的是一種變化趨勢,只要是個確定的數,不論多麼大都與n無關,是常量階,這種當n趨於無限大時都可以忽略。

  • 乘法法則
    嵌套代碼的複雜度等於嵌套內外代碼複雜度的乘積,例如一個n次for循環嵌套另一個n次for循環,時間複雜度爲O(n²)。

常見的複雜度量級
  • 常量階O(1)
    只要代碼不隨n的增大而增大,時間複雜度就是O(1)

  • 對數階O(logn)

  • 線性階O(n)

  • 線性對數階O(nlogn)

  • k次方階O(n^k)

  • 指數階O(2^n)

  • 階乘階O(n!)

空間複雜度

空間複雜度表示算法的存儲空間與數據規模之間的增長關係
空間複雜度的分析同時間複雜度。

最好、最壞情況時間複雜度
  • 最好情況時間複雜度
    在最理想的情況下,執行一段代碼的時間複雜度

  • 最壞情況時間複雜度
    在最糟糕的情況下,執行一段代碼的時間複雜度

平均情況時間複雜度

最好、最壞情況時間複雜度反映的是極端情況下的複雜度,發生的概率不大。平均情況時間複雜度是將每種情況發生的概率考慮進去,將每種情況下的複雜度乘以發生這種情況的概率相加,這個值是概率論中的加權平均值,也叫期望值。所以平均時間複雜度也稱加權平均時間複雜度或期望時間複雜度。

均攤時間複雜度

對一個數據結構進行一組連續的操作,大部分情況下時間複雜度都很低,只有個別情況下時間複雜度比較高,且這些操作之間存在前後連貫的時序關係,這種情況下,我們將這一組操作放在一起分析,看能否將時間複雜度較高的那次操作的耗時,分攤到其他那些時間複雜度低的操作上,這就是攤還分析法。通過攤還分析法得到的時間複雜度,我們稱爲均攤時間複雜度。一般均攤時間複雜度就等於最好時間複雜度。

如上圖,共n+1種情況,每種情況發生的概率都一樣,前n種情況的時間複雜度爲O(1),第n+1種情況的時間複雜度爲O(n),那平均時間複雜度爲O(1)。因此,均攤時間複雜度就是一種特殊的平均時間複雜度。只是針對這種特殊場景,我們不需要再找出所有情況及發生的概率計算加權平均值,能夠快速得到其時間複雜度。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章