【數據結構&算法】02-復雜度分析之執行效率和資源消耗


前言

本筆記主要記錄如何分析、統計算法的執行效率和資源消耗

必須學會分析復雜度分析。

李柱明博客:https://www.cnblogs.com/lizhuming/p/15487271.html

復雜度

復雜度分為:

  1. 時間復雜度。關聯到執行效率

    • 時間復雜度的全稱是 漸進時間復雜度表示算法的執行時間與數據規模之間的增長關系
  2. 空間復雜度。關聯到資源消耗

    • 空間復雜度全稱就是漸進空間復雜度表示算法的存儲空間與數據規模之間的增長關系

分析方法

大 O 復雜度表示法

先說結論:

  • 大 O 復雜度表示方法只是表示一種變化趨勢。
  • 忽略掉公式中的常量、低階、系數,只需要記錄一個最大階的量級就可以了
  • 多、加法和乘法規則

例子-評估累加和的各種算法執行效率

算法 1(for 循環):
int cal(int n) 
{
  int sum = 0;
  int i = 1;
  for (; i <= n; ++i)
  {
    sum = sum + i;
  }
  return sum;
}
  • 從 CPU 角度看:

    • 重復類似的操作:讀數據-運算-寫數據。
    • 假設每行代碼執行事件都為 unit_time。(粗略估計)
    • 代碼中執行的時間為:T(n) = (2+3n)*unit_time
  • 結論:所有代碼的執行時間 T(n) 與每行代碼的執行次數成正比。

算法 2(嵌套 for 循環):
int cal(int n) 
{
  int sum = 0;
  int i = 1;
  int j = 1;
  for (; i <= n; ++i) 
  {
    j = 1;
    for (; j <= n; ++j) 
    {
      sum = sum +  i * j;
    }
  }
}
  • 代碼中執行時間為:T(n) = (3+3n+3n²)*unit_time=3(n²+n+1)*unit_time
  • 所有代碼的執行時間 T(n) 與每行代碼執行的次數成正比。

大 O 表示

T(n) = O(f(n))

  • 上面算法 1 中的大 O 表示法為:T(n) = O(2+3n)

  • 上面算法 2 中的大 O 表示法為:T(n) = O(3(n²+n+1))

  • 大 O 表示法不是表示代碼真正的執行時間,而是表示代碼執行時間隨數據規模增長的變化趨勢

    • 即是時間復雜度

當 n 很大時,公式中的低階常量系數三部分並不左右增長趨勢,所以都可以忽略。

只需要記錄一個最大量級就可以了,如果用大 O 表示法表示剛講的那兩段代碼的時間復雜度,可記為:

  • T(n) = O(n)
  • T(n) = O(n²)

時間復雜度分析

當了解了大 O 表示法后,就可以用來分析時間復雜度了。

三個實用的方法:

  1. 只關注循環執行次數最多的一段代碼。
  2. 加法法則:總復雜度等於量級最大的那段代碼的復雜度。(
  3. 乘法法則:嵌套代碼的復雜度等於嵌套內外代碼復雜度的乘積。(嵌套:

關注執行最多的一段代碼

以上面算法 1 為例:

  • 前面兩行代碼為常量級別,忽略。

  • 3n 中的系數也可忽略。

  • 結論:時間復雜度為 O(n)

算法 2 的時間復雜度就是 O(n²)

加法規則

加法法則:總復雜度等於量級最大的那段代碼的復雜度

  • 公式:T(n)=T1(n)+T2(n)=max(O(f(n)), O(g(n))) =O(max(f(n), g(n)))

若上面算法 1 和算法 2 出現在同一個代碼段中是,其時間復雜度之和為 O(n)+O(n²)

總的時間復雜度就是取最大量級: O(n²)

乘法規則

乘法法則:嵌套代碼的復雜度等於嵌套內外代碼復雜度的乘積

  • 公式:T1(n)=O(f(n))T2(n)=O(g(n));那么 T(n)=T1(n)T2(n)=O(f(n))O(g(n))=O(f(n)*g(n))

例子:

  • 時間復雜度:T(n) = T1(n) * T2(n) = O(n*n) = O(n²)
int func(int n) 
{
 int sum = 0;
 int i = 1;
 for (; i < n; ++i) 
 {
   sum = sum + i;
 } 
 return sum;
}

int cal(int n)
{
  int ret = 0; 
  int i = 1;
  for (; i < n; ++i) 
  {
    ret = ret + func(i);
  } 
} 

常見時間復雜度

常見時間復雜度量級如圖:

這些復雜度量級可分為:

  • 多項式量級:

    • 常量階:O(1)
    • 對數階:O(logn)
    • 線性階:O(n)
    • 線性對數階:O(nlogn)
    • k 次方階:O(nk)注意:這里的 k 為 k 次方)
  • 非多項式量級

    • O(2n);(注意:這里的 n 為 n 次方)
    • O(n!)
    • 說明:當數據規模 n 越來越大時,非多項式量級算法的執行時間會急劇增加,求解問題的執行時間會無限增長。所以,非多項式時間復雜度的算法其實是非常低效的算法

常量階 O(1)

O(1) 只是常量級時間復雜度的一種表示方法,並不是指只執行了一行代碼。

大牛總結:(常量級記作 O(1)

  • 只要代碼的執行時間不隨 n 的增大而增長,這樣代碼的時間復雜度我們都記作 O(1)
  • 或者說, 一般情況下,只要算法中不存在循環語句、遞歸語句,即使有成千上萬行的代碼,其時間復雜度也是 Ο(1)

對數階 O(logn)、O(nlogn)

i=1;
while (i <= n)
{
  i = i * 2;
}

時間復雜度分析過程:

  • 多:第 4 行代碼執行次數最多。那就算出第四行執行的次數。

  • 得 x = log2n 即時間復雜度為 O(log2n)。也就是 O(logn)

  • 不管底數為何值,都把這類對數階的時間復雜度記為 O(logn)。理由:

    • log3n = log32 * log2n。對應時間復雜度為:O(log3n) = O(C * log2n)。
    • 按前面學的系數可忽略:O(log3n) = O(log2n)。
    • 既然不同底數都可以轉化,那就直接使用 O(logn) 來標記對數階。

而對於 O(nlogn) 就是一段時間復雜度為 O(logn) 的代碼段被執行了 n 次。

多參數階 O(m+n)、O(m*n)

分析代碼的時間復雜度由兩個以上數據的規模來決定。

以下以兩個數據規模決定為基礎。

int cal(int m, int n)
{
  int sum_1 = 0;
  int i = 1;
  for (; i < m; ++i)
  {
    sum_1 = sum_1 + i;
  }

  int sum_2 = 0;
  int j = 1;
  for (; j < n; ++j)
  {
    sum_2 = sum_2 + j;
  }
  return sum_1 + sum_2;
}
  • 其時間復雜度為:O(m+n)
  • 對於加法規則(變了):T1(m) + T2(n) = O(f(m) + g(n))。
  • 對於乘法規則(不變):T1(m)*T2(n) = O(f(m) * f(n))。

空間復雜度分析

空間復雜度。關聯到資源消耗

  • 空間復雜度全稱就是漸進空間復雜度表示算法的存儲空間與數據規模之間的增長關系

使用大 O 表示法,和時間復雜度一樣,只是分析的數據規模 n 由時間度量改為空間度量。

小結

復雜度也叫漸進復雜度,包括時間復雜度和空間復雜度,用來分析算法執行效率與數據規模之間的增長關系。

通常越高階復雜度的算法,執行效率越低。

常見的復雜度並不多,從低階到高階有:O(1)、O(logn)、O(n)、O(nlogn)、O(n2 )。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM