小前端學演算法之複雜度分析

冬日陽光66發表於2019-03-19

資料結構和演算法本身解決的是“快”和“省”的問題,即如何讓程式碼執行的更快,如何讓程式碼更省儲存空間。 所以複雜度分析是整個演算法學習的精髓。

大O複雜度表示法

推倒大O階

演算法的執行效率,就是演算法程式碼執行的時間。來估算一下下面程式碼的執行時間。

function sum(n) {
    let total = 0;
    for (let i=0;i < n;i++) {
        total = total + i
    }
    return total;
}
複製程式碼

假設每行程式碼執行的時間都一樣,都是unit_time。

第 2 行程式碼需要 1 個unit_time 的執行時間,第 3、4 行都執行了 n 遍,所以需要 2n*unit_time 的執行時間,所以這段程式碼總的執行時間就是 (2n+1)*unit_time。

可以看出,程式碼的執行時間T(n) 與每行程式碼的執行次數成正比

再來推導下面程式碼的執行時間:

function sum(n) {
    let total = 0;
    for (let i=1;i<=n;i++) {
        for (let j=1;j<=n;j++) {
            total = total + i * j
        }
    }
    return total
}
複製程式碼

同樣第2行需要 1個 unit_time 的執行時間,第3行程式碼迴圈執行了n遍,需要n * unit_time的執行時間,第4、5行執行了n² 遍,所以需要(2n²+n+1)*unit_time 的執行時間。

儘管我們不知道unit_time的具體值,但通過兩段程式碼的執行時間推導過程,我們得到一個非常重要的規律,那就是,所有程式碼的執行時間T(n) 與每行程式碼的執行次數n成正比

T(n) = O(f(n))
複製程式碼

T(n) 代表程式碼執行的時間,n表示資料規模的大小;f(n)表示每行程式碼執行的次數總和。公式中的O,表示程式碼的執行時間T(n) 與f(n) 表示式成正比。

大O時間複雜度實際上並不具體表示程式碼真正的執行時間,而是表示***程式碼執行時間隨資料規模增加變化的趨勢***,所以,也叫做漸進時間複雜度。

當n很大時,公式中的低階、常量、係數三部分並不左右增長的趨勢,所以可以忽略。我們只需要記錄一個最大量級就可以了,所以上面兩段程式碼就可以計作:T(n) = O(n) 和 T(n) = O(n²)。

時間複雜度分析方法

  • 只關注迴圈次數最多的一段程式碼
  • 加法法則:總複雜度等於量級最大的那段程式碼的複雜度
  • 乘法法則:巢狀程式碼的複雜度等於巢狀內外程式碼複雜度的乘積

常見的時間複雜度分析

常數階 O(1)

O(1)只是常量級時間複雜度的一種表示方法,並不是指只執行了一行程式碼,比如下面這段程式碼,即使有3行,他的時間複雜度也是O(1),而不是O(3)。

let i = 2;
let j = 5;
let sun = i + j;
複製程式碼

一般情況下,只要演算法中不存在迴圈語句、遞迴語句,即便有成千上萬行程式碼,其時間複雜度也是O(1)。

線性階 O(n)

下面這段程式碼的時間複雜度為O(n),因為迴圈體中的程式碼需要執行n次。

let sum = 0;
for (let i=0;i<n;i++){
    sum = sum +i
}
複製程式碼

我們要分析演算法的複雜度,關鍵就是要分析迴圈結構的執行情況。上面程式碼因為迴圈體中程式碼需要執行n次,所以時間複雜度為O(n)。

對數階 O(logn) O(nlogn)

對數階時間複雜度非常常見。

let i = 1;
while (i <= n) {
    i = i * 2
}
複製程式碼

從上面程式碼中可用看出,遍歷從1開始,每迴圈一次就乘以2,當i大於n時迴圈結束。由於2的x次方等於n,x = log2n,這個迴圈的時間複雜度就是O(log2n)。不管是以2為底,還是以3為底,我們都可以把所有對數階的時間複雜度計作:O(logn)。

平方階 O(n²)
for (let i=0;i<n;i++) {
    for (let j=o;j<n;j++) {
        /*時間複雜度為O(1)的程式步驟*/
    }
}
複製程式碼

根據迴圈的時間複雜度等於迴圈體的複雜度乘以該迴圈執行的次數。所以上面程式碼的時間複雜度為O(n²)。

image

最優演算法

一般情況下,隨著n的增大,T(n) 增長最慢的演算法為最優演算法。

最壞情況

我們查詢一個有n個隨機數字陣列中的某個數字,最好的情況是陣列的第一個數字就是,那麼演算法的時間複雜度為O(1),但也可能這個數字在最後一位,那麼演算法的時間複雜度就是O(n),這就是最壞情況了。

最壞情況執行時間是一種保證,那就是執行時間不會再壞了。通常除非特別指定,我們提到的執行時間都是最壞情況的執行時間。

本文摘自極客時間王爭老師的 資料結構與演算法之美

摘自《大話資料結構》

相關文章