本文是学习算法的笔记,《数据结构与算法之美》,极客时间的课程
上篇文章说了时间复杂度的问题,这篇文章主要说几个概念
最好情况时间复杂度 (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)。
一般来说,在可以用到均摊时间复杂度的地方,其值等于最好情况时间复杂度。