5. 演算法效能評價指標
Big O notation is a mathematical notation that describes the limiting behavior of a function when the argument tends towards a particular value or infinity.
In computer science, big O notation is used to classify algorithms according to how their run time or space requirements grow as the input size grows.
來自:wiki: big_O_notation
在計算機中,大 O 表示法常作為衡量演算法的執行時間或所需記憶體空間隨輸入規模增長而發生變化的度量;
5.1 時間複雜度的計算(大 O 表示法)
用來衡量執行時間時,它為演算法在最壞情況下執行時間的上界,即為任意規模的資料的執行時間的上界。
例如,插入排序,在資料有序的情況下,時間複雜度為 O(n);如果資料是逆序的,那麼插入排序的時間複雜度就是 O(n^2);對所有資料來說,最差情況下的時間複雜度為 O(n^2),所以稱插入排序的時間複雜度為 O(n^2)。
以上結論和例子據說來自《演算法導論》
常用的計算方法:
- 頻度計演算法:
- 假設所有的語句執行的時間相同,計算所有語句的頻度 T(n);
- T(n) 的最高次項即為 O(f(n))(不需要保留最高次項的常數);
- 一般的計算步驟:
- 找到所有語句中執行次數最多的那條語句作為基本語句;
- 計算基本語句執行次數的數量級;
- 取其數量級用大 O 表示即可;例如 O(n)、O(logn)等等;
- 含有遞迴的時間複雜度的分析:
- 每一次呼叫函式的時間複雜度 * 函式的呼叫次數
在上述程式碼中,每次呼叫函式的時間複雜度為 O(1),呼叫次數為 O(n),所以總的時間複雜度為 O(n);int fact(int n) { if (n <= 1) return 1; return n * fact(n - 1); }
- 每一次呼叫函式的時間複雜度 * 函式的呼叫次數
- 一些特殊的技巧:寫出第 i 次迴圈後,迴圈變數的值;
int func(int n) { int i = 0, sum = 0; while (sum < n) sum += ++i; return i; } /***時間複雜度分析 1: sum = 1 2: sum = 1 + 2 3: sum = 1 + 2 + 3 ... i: sum = i(1+i)/2 < n 因為 sum 要大於等於 n 才退出迴圈, 所以 i 的上界可以為 sqrt(n) ***/ x = 0; while (n >= (x+1)*(x+)) x+=1; /***時間複雜度分析 i: (i+1)*(i+1) <= n O(sqrt(n)) ***/
- 加法法則,乘法法則;
5.2 空間複雜度的計算(大 O 表示法)
-
非遞迴問題的空間複雜度分析
int j = 0; int k = 0; for (int i = 0; i < n; i ++) { j ++; k ++; } /*** 空間複雜度分析 開闢了 i、j、k 三個資料空間,所以空間複雜度為 O(1) ***/ int *a = new int(n); for (int i = 0; i < n; i ++) a[i] = i; /*** 空間複雜度分析 陣列空間隨著 n 的增大而增大,且保持線性的速度, 所以空間複雜度為 O(n) ***/
-
遞迴問題的空間複雜度分析
int fib(int n) { if (n <= 1) return n; else return fib(n - 1) + fib(n - 2); }
遞迴問題的空間複雜度 = 每一層的空間複雜度 * 遞迴深度;
資料結構一般只考慮單個程序單個執行緒的情況,所以上述最大的所需的棧空間為每一層的空間複雜度 * 遞迴深度
int test(int n) { if (n <= 1) return 1; test(n/2); } /*** 空間複雜度分析 每一層的空間複雜度為 O(1),遞迴深度為 O(logn) 所以空間複雜度為 O(logn) ***/
5.3 演算法題:判斷素數、最大連續子序列問題
bool isPrime(int n) {
bool prime = true;
for (int i = 1; i < n; i ++)
if (n % i == 0)
prime = false;
return prime;
}