数据结构与算法第二天

94 阅读6分钟

样例:

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;
    }
}

}

分析:

因为x是未知变量,可能i的为1的时候就找到了x,那这个代码的复杂度就是O(1),也有可能遍历循环完也找不到x那这个代码的复杂度就是O(n),因此代码不同情况下它就有不同的时间复杂度。

最好情况时间复杂度

如样例代码中一样好,最理想情况就是需要查找的x是数组的第一个元素,这样对应的时间复杂度就是最好的时间复杂度

最坏情况时间复杂度

如样例代码中一样,数组中没有x我们需要把整个数组遍历一遍才行,所以这种最糟糕的情况下时间复杂度就是最坏情况时间复杂度

平均情况时间复杂度

最好情况时间复杂度和最坏情况复杂度对应的都是极端情况下的代码复杂度,发生的概率其实并不大,所以需要平均情况复杂度.平均时间复杂度的全称应该叫加权平均时间复杂度或者期望复杂度。

样例分析

要查询变量x在数组中的位置,有n+1中情况,数组的0~n-1位置中和不在数组中,所以有n+1中情况 所以在每种情况下把查询遍历的元素个数累加起来然后除以n+1,就可以得到所需要遍历的元素个数的平均值

image.png

在时间复杂度大O标记法中,可以省略低阶,常量,系数,所以得到平均时间复杂度就是O(n).

在具体分析发现:

要查找X,要么在数组中要么不在数组中,对这个情况概率就是1/2.另外要查找的数据出现在0 ~ n-1这n个位置的概率也是一样的,为1/n.所以概率乘法法则,要查找出现在0~n-1中任意位置的概率就是1/(2n).因此前面的推导过程中没有将各种情况发生的概率考虑进去,如果把每种情况都考虑进去,平均时间复杂度的计算过程就变成

image.png

公式分析

  1. 0 ~ n-1次任意位置出现的概率是1/2n。然后可能有n次概率所以1~n数列求和:n(n+1)/2
    所以:出现的概率:n(n+1)/2n * 1/2n=n+1/4
  2. 不出现在数组中为n的概率又是1/2 * n
  3. 总遍历的次数就是:3n+1/4 公式也可以理解为: 最后两个n,前者代表遍历数组理全部元素找到了x,后面代表遍历数组理的元素有没有找到,所以乘的概率不同
    这个值得概率论中的加权平均值,也叫作期望值,所以平均时间复杂度全称应该叫加权平均时间复杂度或者期望时间复杂度

小结一:

一般情况下载同一块代码的不通情况下时间复杂度有量级的差距,我们才会用三种复杂度表示发来区分

均摊时间复杂度

平均复杂度只在某种特殊情况下才会用到,而均摊时间复杂度应该用的场景比他更加特殊更加有限

样例
  • array表示一个长度为n的数组

  • 代码中的array.length就等于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; } array[count] = val; ++count; }

分析

这是一个往数组理插数据的功能,当数组满了之后,也就是代码中count == array.length时,用for循环遍历数组求和,并清空数组,将求和之后的sum值放到数组的第一个位置,然后再将新的数据插入,但如果数组一开始就有空闲空间,直接将数据插入数组

时间复杂度是多少?最理想的状态数组有空闲空间,我们只需要将数据插入到数组下标为count的位置就可以,所以最好情况复杂度为O(1)。最坏情况下数组中没有空闲空间。我们需要先做一次数组的遍历求和,然后再讲数据插入。最坏的复杂度为O(n)
进一步分析,假设数组的长度是n,根据数据插入的位置不通,我们可以分为n中情况,每一种情况的时间复杂度都是O(1)。除此之外,还有一种"额外"的情况,就是在数组没有空闲空间时插入一个数据,这个事就的时间复杂度O(n) 而且这n+1种情况发生的概率一样,都是1/(n+1).所以加权平均的计算方法,可以得到时间复杂度是:\

image.png

解释

平均时间复杂一般使用加权平均值得计算方发:
1.分析总共的情况
2.分析每种情况发生的概率
3.最后每种请款遍历的元素数目* 该情况的概率,相加;得出平均时间复杂度

1.第一步:1/(n+1)+.... +1/(n+1)=n/(n+1)
2.第二步:n/(n+1)+n/(n+1)=2n/(n+1)
3.第三不:根据复杂度计算,去掉系数n/n为1所以均摊时间复杂度为o(1) 还可以理解为:数组是n,出入不同位置,那就有n种情况,每种情况的时间复杂度是O(1)那么 有没有空闲空间的概率又是n/(n+1).所以平均时间复杂度就是
O(1)* 1/(n+1)+O(1)* 1/(n+1)+.....+O(1)* 1/(n+1) =(O(1)+O(1)+O(1)+....+O(1))* 1/(n+1)=(n+1)* O(1) * 1/(n+1)=O(1)

摊还分析法:

通过摊还分析得到的时间复杂度叫做均摊时间复杂度 样例: 上例数组中插入数据的这个例子,每一次O(n)的插入操作,都会跟着n-1次O(1)的插入操作所以把耗时多的那次 操作均摊到接下来的n-1次耗时少的操作上,均摊下来,这一组连续操作的均摊时间复杂度就是O(1)。

总结:

对一个数据结构进行一组连续操作中,大部分情况下时间复杂度都很低,只有个别情况下时间复杂度比较高,而且这些操作之间存在前后连贯的时序关系,这个时候,我们就可以将这一组操作放在一块分析,看是否能将较高的时间复杂度那次操作的耗时,平摊到其他那些时间复杂度比较低的操作上,而且,在能够应用均摊时间复杂度分析的场合,一般均摊时间复杂度就等于最好情况时间复杂度