極簡教程:數據結構與算法(一)

2020-4-28

這是一套關與數據結構與算法的系列文章,值得你持續關注

時間複雜度與空間複雜度javascript

我儘可能用 最少的文字,最少的代碼。來說明白數據結構與算法。

1. 數據結構與算法是爲了解決 「快」 和 「省」的問題

2. 評估 「快」 和 「省」方法就是 「複雜度分析」

3. 「複雜度分析」 分爲 「時間複雜度」 和 「空間複雜度」

4. 「時間複雜度」 指的是:代碼執行時間 隨着 數據規模 的增加變化趨勢

5. 「空間複雜度」 指的是:存儲空間 與 數據規模 的增加變化趨勢

6. 複雜度分析過程

const findCat = (n) => {
    // 定義變量
    let name = '石興龍';
    let animal = '貓';
    let cat_number = 0
    // n 越大,循環的次數越多
    for (let i = 0; i < n; i++) {
        cat_number++;
    }
    console.log(`${name} 有 ${cat_number} 只貓`)
}
findCat(1)     // 石興龍 有 1 只貓
findCat(10)    // 石興龍 有 10 只貓
findCat(n)     // 石興龍 有 n 只貓

先來看看執行過程。先定義了 3 個變量、其次 for 循環、最後一行打印。假設每一行的執行時間爲 x 。那麼總的執行時間爲:java

T(n) = 3x + for(n) + x算法

其中 3x 和 x 的執行時間是不會變的,和 n 沒有關係,咱們忽略不計。那麼如今的執行時間是:數組

T(n) = for(n) = O(n)數據結構

find 函數的複雜度徹底依賴變量 n 的大小,因此就是 O(n)dom

7. 複雜度大概分爲5種:

| 複雜度 | 執行速度 |
| -- | --|
| O(1) | 最快 |
| O(logn) | 快 |
| O(n) | 慢 |
| O(nLong) | 很慢 |
| O(n次方) | 最慢 |
// 最快的代碼 O(1)
let findCat = () => {
    let name = '石興龍';
    let animal = '貓';
    let cat_number = 0
    let n = 10
    for (let i = 0; i < n; i++) {
        cat_number++;
    }
    console.log(`${name} 有 ${cat_number} 只貓`)
}
findCat() // 石興龍 有 10 只貓 
// 雖然也有 for 循環,可是執行時間是固定的

// 快的代碼 O(logn)
findCat = (n) => {
    let name = '石興龍';
    let animal = '貓';
    let cat_number = 0
    for (let i = 0; i < n; i++) {
        if (i % 2 === 0) {
            cat_number++;
        }
    }
    console.log(`${name} 有 ${cat_number} 只貓`)
}
findCat(10) // 石興龍 有 5 只貓
// logn 函數產生的值 < n

// 慢的代碼 O(n)
findCat = (n) => {
    let name = '石興龍';
    let animal = '貓';
    let cat_number = 0
    for (let i = 0; i < n; i++) {
        cat_number++;
    }
    console.log(`${name} 有 ${cat_number} 只貓`)
}
findCat(10) // 石興龍 有 10 只貓
// 執行的時間 和 n 成正比

// 很慢的代碼 O(nLong)
findCat = (n) => {
    let name = '石興龍';
    let animal = '貓';
    let cat_number = 0
    for (let i = 0; i < n;) {
        i += 0.5;
        cat_number += 1;
    }
    console.log(`${name} 有 ${cat_number} 只貓`)
}
findCat(10) // 石興龍 有 20 只貓
// logn 函數產生的值 > n

// 最慢的代碼 O(n次方)
findCat = (n) => {
    let name = '石興龍';
    let animal = '貓';
    let cat_number = 0
    for (let i = 0; i < n; i++) {
        for (let j = 0; j < n; j++) {
            cat_number++;
        }
    }
    console.log(`${name} 有 ${cat_number} 只貓`)
}
findCat(10) // 石興龍 有 100 只貓
// for 循環的執行次數是 n 的平方,甚至更大

8. 針對某一個算法的複雜度分析又分爲四種狀況: 最快O(1),最慢O(n),均攤O(1),和隨機O(n)

9. 最快,最慢,隨機

let cats = ['鋼蛋兒', '灰灰', '三花', '豆芽']
findCat = (catName) => {
    let name = '石興龍';
    let animal = '貓';
    let cat_number = 0
    for (let i = 0; i < cats.length; i++) {
        if (cats[i] === catName) {
            console.log(`${catName} 排行第 ${i}`)
            break;
        }
    }
    console.log(`${catName} 不是你的貓`)
}
findCat('鋼蛋兒') // 鋼蛋兒 排行第 1
// 執行效率最快 O(1)

findCat('豆芽') // 豆芽 排行第 4
// 執行效率最慢 O(n)

findCat(parseInt(Math.random() * cats.length))
// 平均執行效率爲 O(n),由於是隨機的

10. 均攤 O(1):循環有規律的出現,而且能被抵消掉。

// 插入貓,擴容數組
let index = 4
let insertCat = (newCatName) => {
    if (index === cats.length) {
        let newCats = []
        for (let i = 0; i < cats.length; i++) {
            newCats.push(cats[i])
        }
        cats = newCats
    }
    index++;
    cats.push(newCatName)
}
insertCat('金漸層') // 複雜度:O(n)
insertCat('海雙布偶') // 複雜度:O(1)
insertCat('藍白高地') // 複雜度:O(1)
/*
    均攤:雖然有循環,可是循環是有規律的。
    每一次 O(n) 的後面都跟着 n - 1 次 O(1)
*/

my_wechart.jpg
share.jpg

相關文章
相關標籤/搜索