【資料結構和演算法】3~5 時間複雜度和空間複雜度
演算法效率的度量方法
容易想到的方法是:把演算法跑若干次,然後拿個計時器在旁邊計時。這種方法被稱為“事後諸葛亮”方法,也稱為事後分析估算方法。
事前分析估算方法:在計算機程式比編寫前,依據統計方法對演算法進行估算。
通過總結,我們發現,一個高階語言編寫程式在計算機上執行所消耗的時間取決於下列因素:
(1)演算法採用的策略,方案;
(2)編譯產生的程式碼質量;
(3)問題的輸入規模;
(4)機器執行指令的速度;
由上,拋開計算機硬體、軟體因素,一個程式執行時間依賴於演算法的好壞和問題輸入的規模;
高斯求和演算法:1+2+...+n的問題
演算法1
int i, sum = 0, n = 100; // 執行1次 for( i=1; i <= n; i++ ) // 執行了n+1次 { sum = sum + i; // 執行n次 }
演算法2:
int sum = 0, n = 100; // 執行1次
sum = (1+n)*n/2; // 執行1次
如果我們把迴圈看做一個整體,忽略頭尾判斷的開銷,那麼這兩個演算法其實就是n和1的差距;
函式的漸近增長
假設兩個演算法的輸入規模都是n,演算法A要做2n+3次操作,你可以這麼理解:先執行n次的迴圈,執行完成後再有一個n次的迴圈,最後有3次運算。
演算法B要做3n+1次操作,理解同上,你覺得它們哪一個更快些呢?
規模 |
演算法A1(2n+3) |
演算法A2(2n) |
演算法 |
演算法B2(3n) |
n=1 |
5 |
2 |
4 |
3 |
n=2 |
7 |
4 |
7 |
6 |
n=3 |
9 |
6 |
10 |
9 |
n=10 |
23 |
20 |
31 |
30 |
n=100 |
203 |
200 |
301 |
300 |
函式的漸近增長:
函式的漸近增長:給定兩個函式f(n)和g(n),如果存在一個整數N,使得對於所有的n>N,f(n)總是比g(n)大,那麼,我們說f(n)的增長漸近快於g(n);
第二個測試,演算法C是4n+8,演算法D是2n^2+1
次數 |
演算法C1(4n+8) |
演算法C2(n) |
演算法D1(2n^2+1) |
演算法D2(n^2) |
n=1 |
12 |
1 |
3 |
1 |
n=2 |
16 |
2 |
9 |
4 |
n=3 |
20 |
3 |
19 |
9 |
n=10 |
48 |
10 |
201 |
100 |
n=100 |
408 |
100 |
20001 |
10000 |
n=1000 |
4008 |
1000 |
2000001 |
1000000 |
演算法的時間複雜度
定義:在進行演算法分析時,語句總的執行次數T(n)是關於問題規模n的函式,進而分析T(n)隨n的變化情況並確定T(n)的數量級。演算法的時間複雜度,也就是演算法的時間度量,記作:T(n)=0(f(n))。它表示隨問題規模n的增大,演算法執行時間的增長率和f(n)的增長率相同,稱作演算法的漸近時間複雜度,簡稱為時間複雜度。其中f(n)是問題規模n的某個函式。
關鍵:執行次數==時間
推導大O階方法
如何分析一個演算法的複雜度呢?如何推導大O階呢?有以下攻略:
(1)用常數1取代執行時間中的所有加法常數;
(2)在修改後的執行次數函式中,只保留最高項;
(3)如果最高項存在且不為1,則去除與這個項相乘的常數;
常見的時間複雜度:
例子 |
時間複雜度 |
裝逼術語 |
5201314 |
O(1) |
常數階 |
3n+4 |
O(n) |
線性階 |
3n^2+4n+5 |
O(n^2) |
平方階 |
3log(2)n+4 |
O(logn) |
對數階 |
2n+3nlog(2)n+14 |
O(nlogn) |
nlogn階 |
n^3+2n^2+4n+6 |
O(n^3) |
立方階 |
2^n |
O(2^n) |
指數階 |
有圖有真相:
常用的時間複雜度所耗費的時間從小到大依次是:O(1) < O(logn) < (n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)
演算法的空間複雜度
演算法的空間複雜度通過計算演算法所需的儲存空間實現,演算法的空間複雜度的計算公式記作:S(n)=O(f(n)),其中,n為問題的規模,f(n)為語句關於n所佔儲存空間的函式。
通常,我們都是用“時間複雜度”來指執行時間的需求,是用“空間複雜度”指空間需求。
當直接要讓我們求“複雜度”時,通常指的是時間複雜度。
顯然對時間複雜度的追求更是屬於演算法的潮流
★ finished by songpl 2018.11.24