第3课:算法复杂度分析(下):最好、最坏、平均、均摊时间复杂度

最好、最坏时间复杂度

我们先看一个例子:

/*
 例1:查找x在数组中出现的位置,如果没有找到,返回-1。n表示数组array的长度
*/
int findIndex(int[] array, int n, int x) {
  int i = 0;
  int index = -1;
  for (; i < n; ++i) {
    if (array[i] == x) {
       index = i;
       //break; //暂时注释掉此行
    }
  }
  return index;
}

当把break语句注释掉的时候,总是需要遍历整个数组,所以时间复杂度就是数组的长度,为O(n)。
当有break语句的时候,如果找到x,则会提前退出(显然这种写法更高效)。
我们知道x可能出现在数组的任何位置,可能是第一个(时间复杂度为O(1)),可能是最后一个(时间复杂度为O(n)),也可能不存在数组中(时间复杂度为O(n))。

为了表示代码在不同情况下的不同时间复杂度,我们需要引入三个概念:
最好情况时间复杂度、最坏情况时间复杂度和平均情况时间复杂度。

最好情况时间复杂度 就是,在最理想的情况下,执行这段代码的时间复杂度。
最坏情况时间复杂度 就是,在最糟糕的情况下,执行这段代码的时间复杂度
最好、最坏都是在对应的都是极端情况下的代码复杂度,发生的概率其实并不大。

平均情况时间复杂度

平均时间复杂是为了更好地表示平均情况下的复杂度。
还是上面例1,结合概率知识,我们知道,要查找的变量x在数组中的位置,有 n+1 种情况:在数组的0~n-1位置中和不在数组中。
我们暂且认为每种情况发生的概率都一样为:1/(n+1)。
每种情况的时间复杂度为:1/(n+1)*1、1/(n+1)*2、1/(n+1)*3…1/(n+1)*n、1/(n+1)*n
所以平均时间复杂度为:(所有情况下的时间复杂度的总和)/(总情况数),即:
平均时间复杂度.png
大O表示法中,可以省略掉系数、低阶、常量,所以,得到的平均时间复杂度就是 O(n)。

其实上面的概率并不都是:1/(n+1)。
要查找的变量 x,要么在数组里,要么就不在数组里。
我们假设在数组中与不在数组中的概率都为 1/2。
查找的数据出现在 0~n-1,这 n 个位置的概率也是一样的,为 1/n,则每种情况出现的概率为1/(2n)。
每种情况的时间复杂度为:1/(2n)*1、1/(2n)*2、1/(2n)*3…1/(2n)n
查找的数据不再数组里,则概率为1/2。时间复杂度为:1/2
n。
所以平均时间复杂度为:(所有情况下的时间复杂度的总和)/(总情况数),即:
平均时间复杂度.png
去掉系数和常量,这段代码的加权平均时间复杂度仍为 O(n)。
这个值就是概率论中的 加权平均值,也叫作 期望值,所以平均时间复杂度的全称应该叫 加权平均时间复杂度或者 期望时间复杂度

均摊时间复杂度

均摊时间复杂度,听起来跟平均时间复杂度有点儿像。
对于初学者来说,这两个概念确实非常容易弄混。

/*
 例2:n表示数组长度,count表示数组存储数据的个数
 往数组中添加数据,如果数组满了,则依次打印出来,然后清空数组
*/
int[] array = new int[n];
int count = 0;
void insert(int val) {
        if (count == array.length) {
            for (int i = 0; i < array.length; ++i) {
                System.out.println(array[i]);
            }
			System.out.println(val);
			array = new int[n];
			count = 0;
        } else {
			array[count] = val;
			count++;
		}
}

分析下前面说的三种时间复杂度。
最好:最理想的情况下数组空闲,时间复杂度为O(1)
最差:数组恰好不空闲,时间复杂度是 O(n)
平均:假设数组的长度是 n,根据数据插入的位置的不同,我们可以分为 n 种情况,
每种情况的时间复杂度是 O(1)。除此之外,还有一种“额外”的情况,就是在数组没有空间时插入一个数据,这个时候的时间复杂度是 O(n)。而且,这 n+1 种情况发生的概率一样,都是 1/(n+1)。所以,根据加权平均的计算方法,我们求得的平均时间复杂度就是:
平均时间复杂度.png
其实平均复杂度分析其实并不需要这么复杂,不需要引入概率论的知识。
相对例1的findIndex()函数:findIndex()函数在极端情况下,复杂度才为 O(1)。
但 insert() 在大部分情况下,时间复杂度都为 O(1)。只有个别情况下复杂度才为 O(n)
不知道你有没有注意到,对于 insert() 函数来说,O(1) 时间复杂度的插入和 O(n) 时间复杂度的插入,
出现的频率是非常有规律的,而且有一定的前后时序关系,一般都是一个 O(n) 插入之后,紧跟着n个 O(1) 的插入操作,循环往复。
针对这样一种特殊场景的复杂度分析,我们并不需要像之前讲平均复杂度分析方法那样,找出所有的输入情况及相应的发生概率,然后再计算加权平均值。
而是用一种更加简单的分析方法:摊还分析法,通过摊还分析得到的时间复杂度我们起了一个名字,叫均摊时间复杂度

那究竟如何使用摊还分析法来分析算法的均摊时间复杂度呢?
每一次 O(n) 的插入操作,都会跟着 n次 O(1) 的插入操作,
所以把耗时多的那次操作均摊到接下来的 n 次耗时少的操作上,均摊下来,
这一组连续的操作的均摊时间复杂度就是 O(1)。这就是均摊分析的大致思路。

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

小结

  • 同一段代码,在不同输入的情况下,复杂度量级有可能是不一样的。所以有了最好、最坏、平均、均摊时间复杂度。
  • 其中最好、最坏情况下的时间复杂度分析起来比较简单。平均、均摊两个复杂度分析相对比较复杂。
  • 在大多数情况下,我们并不需要区分最好、最坏、平均情况时间复杂度三种情况。很多时候,我们使用一个复杂度就可以满足需求了。只有同一块代码在不同的情况下,时间复杂度有量级的差距,我们才会使用这三种复杂度表示法来区分。
  • 平均复杂度只在某些特殊情况下才会用到,而均摊时间复杂度应用的场景比它更加特殊、更加有限。
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
算法复杂度包括时间复杂度和空间复杂度时间复杂度是用来评估算法运行时间的指标,主要关注算法的执行步骤和操作次数。常见的时间复杂度有最好时间复杂度最坏时间复杂度平均时间复杂度均摊时间复杂度。一般情况下,我们主要关注最坏时间复杂度。 空间复杂度是用来评估算法所需的额外空间的指标,主要关注算法在执行过程中所占用的内存空间大小。空间复杂度的计算通常是指算法实际占用的额外空间与问题规模之间的关系。常见的空间复杂度表示为S(n)=O(f(n)),其中n为问题规模,f(n)表示算法所需的额外空间。 因此,评价一个算法的效率主要是看它的时间复杂度和空间复杂度情况时间复杂度描述了算法执行所需的时间资源,而空间复杂度描述了算法执行所需的空间资源。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [时间复杂度与空间复杂度解析](https://blog.csdn.net/qq_43558142/article/details/88082705)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [算法时间复杂度和空间复杂度](https://blog.csdn.net/ChineseSoftware/article/details/122573570)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值