《資料結構》學習筆記二:演算法(二)
繼續上節的學習,我們在這一篇文章裡把“演算法”這一章內容學習完。
本節解決問題:
演算法的好壞到底是如何評估的?
知識點:
1.函式的漸進增長
2.演算法的時間複雜度
3.常見的時間複雜度
4.演算法的空間複雜度
1.函式的漸進增長
這一知識點與數學相關,不過沒關係都是很容易理解的內容。
問題: 假如兩個演算法的輸入規模都是n, A的執行次數是 2n +3, B 的執行次數是 3n + 1,那麼這兩個演算法哪一個更好呢?
我們來分析一下,用數學的折線圖更夠很直觀的看到了。

image.png
這裡先給出漸近增長的概念。
輸入規模n在沒有限制的情況下,只要超過一個數值N,這個函式就總是大於另一個函式,我們稱函式是漸近增長的。
函式的漸近增長: 給定兩個函式f(n)和g(n),如果存在一個整數N,使得對於所有的n>N,f(n) > g(n),那麼我們就說f(n)的漸近增長快於g(n)。
從圖中可以看出,隨著n的增大,後面的 +3, 和 +1 對結果的影響並不大。同樣的,與最高次項相乘的的常數也不是很重要。
我們再看一個例子:
演算法 C是 2n^2, D是n^2 + 3n ,我們在來看看他們的曲線圖。

image.png
從圖中可以看出,最高次項的指數大的,函式隨著n的增長,結果也會變得增長的特別快。
於是我們總結出,判斷一個演算法的效率時,函式中的常數和其他次要項常常可以忽略,而更加關注主要項(最高階項)的階數。
2. 演算法的時間複雜度
定義:在進行演算法分析時,語句總的執行次數T(n)是關於問題規模n的函式,進而分析T(n)隨著n變化的情況並確定T(n)的數量級。記做: T(n) = O(f(n))。
這樣用大寫的O()來提現演算法時間複雜度的記法,我們稱為大O記法。一般情況下,T(n)增長的最慢的就是最優演算法。
推導大O階的方法:
- 用常數 1 取代所有的加法常數;
- 在修改後的函式中,只保留最高階項;
3.如果最高階項存在且不是1,則去除與這個項相乘的常數,得到的結果就是最終的大O階。
例如:

image.png
下面我們看幾個常見的時間複雜度。
1》常數階
執行的次數與n無關,這樣的時間複雜度就是常數階,根據大O階的記法,記做O(1) 。
注意: 不管這個常數是多少,我們都記做O(1), 而不是 O(3), O(12)等。
2》 線性階( O(n) )
線性階的迴圈結構要複雜的多。分析演算法的複雜度,關鍵是要分析迴圈結構的執行情況。
3》 對數階
例如:
var i = 1, n3 = 100 while i < n3 { i = i * 2 } print("i = \(i)")
這個迴圈的複雜度是 O(logn)。

image.png
4》平方階
let x = 10, y = 10 for i in 0..<x { for i in 0..<y { print("hello") } }
時間複雜度為 O(n^2) 。
3. 常見的時間複雜度

111.jpg
4. 演算法的空間複雜度
演算法的空間複雜度通過計算演算法所需的儲存空間實現,演算法的空間複雜度的計算公式記做: S(n) = O(f(n)) 。
n:問題的規模(輸入)
f(n): 關於n所佔儲存空間的函式。
通常,我們都是用“時間複雜度”來指執行時間的需求,使用“空間複雜度”指空間需求。當不用限定詞地使用“複雜度”時,通常是指時間複雜度。