【小豬佩奇漫畫】| 複雜度分析原來那麼簡單!
所有程式碼的「執行時間 T(n)」 與每行程式碼的「執行次數n」 成正比【T(n) = O(f(n)) 】。
#####2、分析的三個方法 ■ 最多法則
忽略掉公式中的常量、低階、係數,取最大迴圈次數就可以了,也就是迴圈次數最多的那行程式碼。
▍Example
1 // 求n個數字之和 2 int xiaolu(int n) { 3int sum = 0; 4for (int i = 1; i <= n; ++i) { 5sum = sum + i; 6} 7return sum; 8 } 複製程式碼
▍分析 第二行是一行程式碼,也就是常量級別,與 n 沒有關係,可以忽略,四、五行程式碼是我們重點分析物件,與 n 有關,時間複雜度就是反映執行時間和 n 資料規模的關係。求 n 個數據之和需要執行 n 次。所以時間複雜度為 O(n)。
■ 加法法則
總複雜度等於迴圈次數最多的那段複雜度。
▍Example
1 int xiaolu(int n) { 2int sum = 0; 3//迴圈一 4for (int i = 1; i <= 100; j++) { 5sum = sum + i; 6} 7//迴圈二 8for (int j = 1; j <= n; j++) { 9sum = sum + i; 10} 11 } 複製程式碼
▍分析 上邊有兩個迴圈,一個迴圈 100 次,另一個迴圈 n 次,我們選擇迴圈次數最多的那一個且和「資料規模 n 」相關的迴圈。由上可知,我們很容易選出迴圈二,即和資料規模 n 有關,迴圈次數最多,迴圈次數最多的那段程式碼時間複雜度就代表總體的時間複雜度,為 O(n) ;
■ 乘法法則
當我們遇到巢狀的 for 迴圈的時候,怎麼計算時間複雜度呢?那就是內外迴圈的乘積。
▍Example
1 for (int j = 1; j <= n; j++) { 2for(int i = 1; i <= n; i++) 3sum = sum + i; 4 } 複製程式碼
▍分析 外迴圈一次,內就迴圈 n 次,那麼外迴圈 n 次,內就迴圈 n*n 次。所以時間複雜為 O(n²)。
空間複雜度
1、什麼是空間複雜度?
表示演算法的「儲存空間」與「資料規模」之間的增長關
▍Example
int i = 0; int[] a = new int[n]; for (i; i <n; ++i) { a[i] = i * i; } 複製程式碼
▍分析 在所有程式碼中,我們很容易尋找到儲存空間相關的程式碼,就是第二行,申請了一個 n 大小的儲存空間,所以空間複雜度為 O(n)。
2、最常見的空間複雜度
O(1)、O(n)、O(n²)。
■ O(1)
常量級的時間複雜度表示方法,無論是一行程式碼,還是多行,只要是常量級的就用 O(1) 表示。
▍Example
1 int i = 1; 2 int j = 2; 3 int sum = i + j; 複製程式碼
▍分析 因為這三行程式碼,也就是常量級別的程式碼不隨 n 資料規模的改變而改變。(迴圈、遞迴除外)
■ O(logn) | O(nlogn)
「對數階時間複雜度」,最難分析的一種時間複雜度。
▍Example
1 i=1; 2 while (i <= n){ 3i = i * 3; 4 } 複製程式碼
▍分析 要求這段程式碼的時間複雜度就求這段程式碼執行了多少次,看下圖具體分析。
▍補充 不管是以 2 為底、以 3 為底,還是以 10 為底,可以把所有對數階的時間複雜度都記為 O(logn),因為對數之間可以轉換的,參照高中課本。
■ O(m+n) | O(m*n)
參照上邊講到的加法和乘法法則。
1、最好、最壞時間複雜度
所謂的最好、最壞時間複雜度分別對應程式碼最好的情況和最壞的情況下的執行。
▍Example
1 //在一個 array 陣列中查詢一個數據 a 是否存在 2for (int i = 1; i < n; i++) { 3if (array[i] == a) { 4return i; 5} 6 } 複製程式碼
▍分析 ① 最好情況就是陣列的第一個就是我們要查詢的資料,上邊程式碼之執行一遍就可以,這種情況下的時間複雜度為最好時間複雜度,為 O(1)。
② 最壞的情況就是陣列的最後一個才是我們要查詢的資料,需要迴圈遍歷 n 遍陣列,也就對應最壞的時間複雜度為 O(n)
2、平均時間複雜度
平均時間複雜度需要藉助概率論的知識去分析,也就是我們概率論中所說的加權平均值,也叫做期望值。
▍分析 比如上方的例子,假設我們查詢的資料在陣列中的概率為 1/2;出現在陣列中的概率為 n/1,根據下邊的公式就可以算出出現的概率為 1/2n
然後我們再把每種情況考慮進去,就可以計算出平均時間複雜度。
■ 幾種複雜度效能對比