數據結構與算法(一):時間複雜度與空間複雜度

寫在前面:

該系列博客,是本人系統學習數據結構以及算法的筆記類博客,用於記錄一些知識點以及自己所實現的代碼,以作備忘,歡迎批評交流。

下面開始正文,介紹一下數據結構及算法的入門定義。

目錄

1. 什麼是數據結構、算法

2. 複雜度分析

2.1 時間複雜度

2.2. 空間複雜度

3. 最好、最壞、平均、均攤時間複雜度


1. 什麼是數據結構、算法

簡而言之,數據結構就是數據的存儲結構,算法就是操作這些數據的方法

兩者都是前人爲了更高效、更節省空間地進行數據處理而創造的,所聚焦的是“快”和“省”兩個字。

2. 複雜度分析

既然已經知道,數據結構和算法是爲了快且省地進行數據操作,那麼就需要一個指標來評價你的算法到底有多快、多省。

複雜度分析即是爲此而生,包括時間複雜度分析、空間複雜度分析兩種。

主要用到大O分析法:T(n) = O(f(n)),表示的是複雜度的量級,也即不是具體的時間、內存消耗,而是其消耗與數據規模n相關的量級。

常用的複雜度有:常量階:O(1) 對數階:O(log_n) 線性階:O(n) 線性對數階:O(nlogn) k次方階: 指數階: 階乘階:

  • 常量階:O(1)
  • 對數階:O(logn)
  • 線性階:O(n)
  • 線性對數階:O(nlogn)
  • k次方階:O(n^k)
  • 指數階:O(2^n)
  • 階乘階:O(n!)

2.1 時間複雜度

分析時間複雜度時,需要假設每一個單元操作是一個單位時間,然後只需要統計整個程序的操作次數再取最大量級即可。

下面列舉幾種複雜度的程序,即可一目瞭然:

// 程序A:
int a=1;
int b=2;

// 程序B:
int i=1;
while (i <= n)  {
   i = i * 2;
 }

// 程序C:
int i=1;
int sum=0;
while (i <= n)  {
   sum += i;
}

對於程序A,執行了兩句話,其量級是常量,因此時間複雜度爲O(1)

對於程序B,執行了log_2n次,因此其時間複雜度爲O(logn)

對於程序C,則執行了n次,因此其時間複雜度爲O(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).

對於嵌套代碼的複雜度,等於嵌套內外代碼複雜度的乘積。這個不難理解,想象一個雙重for循環:


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

其時間複雜度爲:O(n^2).

2.2. 空間複雜度

空間複雜度主要從程序運行過程所申請內存大小來判斷,表示算法的存儲空間與數據規模之間的增長關係。

以上述程序A爲例,其空間複雜度爲O(1)。再舉個例子:

int n = 1000;
int[] a = new int[n];

其空間複雜度則爲O(n),因爲申請了n個int型內存空間。

3. 最好、最壞、平均、均攤時間複雜度

空間複雜度不必多講,對於時間複雜度,有時候需要考慮不同情況下複雜度的不同,主要分爲:最好、最壞、平均、均攤幾種。

最好情況時間複雜度:在最理想的情況下,執行這段代碼的時間複雜度;

最壞情況時間複雜度:在最糟糕的情況下,執行這段代碼的時間複雜度;

平均時間複雜度:各種情況下的平均情況;

以代碼爲例:


// n表示數組array的長度
int find(int[] array, int n, int x) {
  int i = 0;
  int pos = -1;
  for (; i < n; ++i) {
    if (array[i] == x) {
       pos = i;
       break;
    }
  }
  return pos;
}

可簡單得出:最好情況下,時間複雜度爲O(1),最壞情況下爲O(n)

而平均時間複雜度呢,上述代碼中,是用於查找數組中指定元素的程序,所以分兩種情況:x在數組中、x不在數組中,假設每種情況的概率爲1/2,對於在數組中的情況,x在數組各個位置的概率又爲1/(2n),因此把所有情況加起來即爲:

1*\tfrac{1}{2n} +2*\tfrac{1}{2n}+....+n*\tfrac{1}{2n} + n*\tfrac{1}{2} = \tfrac{3n+1}{4}

因此,平均時間複雜度也爲O(n)

此外,還有一個概念——均攤時間複雜度。這個概念是用於描述好情況、壞情況有規律重複的時候,將壞情況複雜度直接均攤給所有簡單情況,從而計算時間複雜度的方法。

比如:對於一組規模爲n的數據,前n-1中情況,都是複雜度爲O(1),第n種情況複雜度爲O(n),則利用均攤計算方法,其均攤時間複雜度爲O((n+1)/n) = O(1).

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章