1. 程式人生 > >複雜度分析(進階版)

複雜度分析(進階版)

本文是學習演算法的筆記,《資料結構與演算法之美》,極客時間的課程

上篇文章說了時間複雜度的問題,這篇文章主要說幾個概念
最好情況時間複雜度 (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)。

一般來說,在可以用到均攤時間複雜度的地方,其值等於最好情況時間複雜度。