演算法複雜度分析(上)

dannab發表於2018-09-27

為什麼需要演算法複雜度分析?

首先,這和研究資料結構和演算法的目的有關——“快”而“省”的解決問題。那麼如何衡量演算法的效能呢?就需要演算法複雜度分析。

其次,除了演算法複雜度分析,還有一種方法可以衡量複雜度,那就是“事後統計法”,即直接執行程式,統計需要的時間和空間。但是,這種方法有兩個問題:

1)結果非常依賴於測試環境。比如,用 Core i3 和用 Core i8 執行程式所需的時間是不同的;

2)結果受測試規模的影響特別大。比如,對有序陣列進行排序的時間比對逆序陣列排序的時間短;對於小規模資料而言,插入排序所需時間比快速排序要短。

所以,就需要有一種不用具體測試資料,也能估計演算法執行效率的方法,就是演算法複雜度分析,包括時間、空間複雜度分析。

大 O 複雜度表示法

大 O 複雜度表示法可以歸納成下面一句話:

所有程式碼的執行時間 T(n) 與每行程式碼的執行次數 n 成正比。

T(n) = O(f(n))。其中,f(n) 表示程式碼的執行次數之和。大 O 符號(Big O notation)是用於描述函式漸進行為的數學符號,它代表“order of...”(...階)。

例如,對於程式碼:

function foo (n) {
    var i = 0;
    var j = 0;
    for (; i < n; i++) {
        j += i;
    }
}
複製程式碼

假設每行程式碼的執行時間一樣,為 unit_time。則第 2、3 行執行時間均為 1 unit_time,第 4、5 行程式碼執行時間均為 n unit_time,整個函式的執行時間 T(n) = (2n + 2) * unit_time。用大 O 複雜度表示法表示即為 T(n) = O(2n + 2)

注意,大 O 時間複雜度並不具體表示程式碼真正的執行時間,而是表示程式碼執行時間隨資料規模增長的變化趨勢。所以,它也叫漸進時間複雜度,簡稱時間複雜度。

當 n 很大時,不左右增長趨勢的低階、常量、係數均可忽略。所以,上面例子中的時間複雜度為 O(n)

時間複雜度分析

時間複雜度分析有下面幾個原則:

1)只關注迴圈執行次數最多的一段程式碼;

2)加法原則:總複雜度等於量級最大的那段程式碼的複雜度。用公式表示即為:T1(n) = O(f(m)),T2(n) = O(g(n)),T1(n) + T2(m) = O(max(f(n), g(m)))

3)乘法原則:巢狀程式碼的複雜度等於巢狀內外程式碼複雜度的乘機。用公式表示即為:T1(n) = O(f(m)),T2(n) = O(g(n)),T1(n) * T2(m) = O(f(n) * g(m))

常見的時間複雜度有以下幾種:

1)常量階:O(1)

2)對數階:O(logn)

3)線性階:O(n)

4)線性對數階:O(nlogn)

5)平方階:O(n ^ 2)

6)指數階:O(2 ^ n)

7)階乘階:O(n!)

其中,1)-5)為多項式量級;6)、7)為非多項式量級,所對應的演算法問題被稱為非確定多項式問題(NP 問題,Non-Deterministic Polynomial)。

空間複雜度分析

空間複雜度全稱為漸進空間複雜度(asymptostic space complexity)。空間複雜度較為簡單,常見的空間複雜度為 O(1)O(n)O(n ^ 2)

最後,用幾種複雜度的座標圖作為結尾:

演算法複雜度分析(上)


本文是《資料結構與演算法之美》的讀書筆記

演算法複雜度分析(上)

首發於微信公眾號《程式碼寫完了》

演算法複雜度分析(上)

相關文章