複雜度分析(進階版)
本文是學習演算法的筆記,《資料結構與演算法之美》,極客時間的課程
上篇文章說了時間複雜度的問題,這篇文章主要說幾個概念
最好情況時間複雜度 (best case time complexity)
最壞情況時間複雜度(worst case time complexity)
平均情況時間複雜度(average case time complexity)
均攤時間複雜度(amortized time complexity)
// n 表示資料a 的長度 int find(int[] a , int n, int x){ int pos = -1; int i = 0; for(; i<n; i++){ if(a[i] = x){ pox = i; break; } } return pos; }
這段程式碼就是找出x 在陣列a中的位置並返回,如果不在陣列中則返回-1
如何分析這段程式碼的複雜度,假設x是陣列的第一個元素,那麼時間複雜度就是O(1),它就對應最好情況時間複雜度。如果x是陣列的最後一個元素,那時間複雜度就是O(n),它就對應最壞時間複雜度。
那什麼是平均情況時間複雜度呢?為了方便計算,元素x是陣列內元素的概率為p, 等於每個元素的概率就是1/np,那麼求出在數組裡的加權平均數 1* 1/np + 2* 1/np +……+n * 1/np = (1+n)/2p,若在陣列外,複雜度為 (n+1)*(1-p)。總的時間複雜度就是(n+1)*常數 即為0(n)
至於均攤時間複雜度,運用場景是很少的,有點複雜。前面的幾個概念掌握基本就夠用了。簡單說下,看下面的虛擬碼。(只是為了說明這種情況,實際上,沒人會這麼寫程式碼)
int[] array = new int[n];
int count = 0;
void insert(int val){
if(count == array.length){
int sum = 0;
for(int i = 0; i < array.length : i++){
sum = sum + array[i]
}
array[0] = sum;
count = 1;
}
}
解析下這段程式碼,往一個數組中插入資料,當陣列有空閒的空間,就直接插入。若沒有,就把求出陣列元素的和,再清空陣列,把這個和賦值給陣列的第一個元素。
複雜度分析,最好情況,數組裡有空間,直接插入,最好情況時間複雜度為O(1),最壞情況,陣列沒有空間了,需要做一次陣列遍歷之後求和,最壞情況時間複雜度為O(n)。平均情況時間複雜度,可有前面講的概率的方法計算,是O(1)。
陣列長度為n,就有n個位置可供插入,還有一種情況是陣列插滿了。總共(n+1)種情況,每種情況概率就是1/(n+1)。 就是n個1 * 1/(n+1)相加,然後再加上 n * 1/(n+1) 最後算出來就是O(1)。
這個insert()方法很特殊,很有規律,n 個時間複雜度為O(1)之後,緊跟著一個時間複雜度O(n),迴圈往復。這時,可引入簡單的均攤時間複雜度來分析,可以不用複雜的加權平均數求平均情況時間複雜度。大概可以這麼理解,把一個O(n)操作,均分到n個o(1)操作,總體上就得到o(1)。
一般來說,在可以用到均攤時間複雜度的地方,其值等於最好情況時間複雜度。