目录

  • 最好、最坏时间复杂度
  • 平均情况时间复杂度
  • 均摊时间复杂度
  • 小结

最好、最坏时间复杂度

我们先看一个例子:

/*例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
所以平均时间复杂度为:(所有情况下的时间复杂度的总和)/(总情况数),即:

大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。
所以平均时间复杂度为:(所有情况下的时间复杂度的总和)/(总情况数),即:

去掉系数和常量,这段代码的加权平均时间复杂度仍为 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)。所以,根据加权平均的计算方法,我们求得的平均时间复杂度就是:

其实平均复杂度分析其实并不需要这么复杂,不需要引入概率论的知识。
相对例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)。这就是均摊分析的大致思路。

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

小结

  • 同一段代码,在不同输入的情况下,复杂度量级有可能是不一样的。所以有了最好、最坏、平均、均摊时间复杂度。
  • 其中最好、最坏情况下的时间复杂度分析起来比较简单。平均、均摊两个复杂度分析相对比较复杂。
  • 在大多数情况下,我们并不需要区分最好、最坏、平均情况时间复杂度三种情况。很多时候,我们使用一个复杂度就可以满足需求了。只有同一块代码在不同的情况下,时间复杂度有量级的差距,我们才会使用这三种复杂度表示法来区分。
  • 平均复杂度只在某些特殊情况下才会用到,而均摊时间复杂度应用的场景比它更加特殊、更加有限。

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

  1. 算法复杂度((平均,最好,最坏,均摊)时间复杂度,空间复杂度)

    文章目录 前言 时间&空间复杂度 时间复杂度 1.最好情况时间复杂度(best case time complexity) 2.最坏情况时间复杂度(worst case time comple ...

  2. 算法复杂度分析(下)

    前一篇文章算法复杂度分析(上)讲述了复杂度的大 O 表示法和几个分析原则,这篇文章我们来讲讲另外几种复杂度,最好情况时间复杂度(best case time complexity).最坏情况时间复杂度 ...

  3. 【数据结构与算法-java实现】二 复杂度分析(下):最好、最坏、平均、均摊时间复杂度的概念

    上一篇文章学习了:如何分析.统计算法的执行效率和资源消耗? 点击链接查看上一篇文章:复杂度分析上 今天的文章学习以下内容: 最好情况时间复杂度 最坏情况时间复杂度 平均情况时间复杂度 均摊时间复杂度 ...

  4. 04 | 复杂度分析(下):浅析最好、最坏、平均、均摊时间复杂度

    // n表示数组array的长度 int find(int[] array, int n, int x) {int i = 0;int pos = -1;for (; i < n; ++i) { ...

  5. 算法复杂度分析(下):最好、最坏、平均、均摊等时间复杂度概述

    细化时间复杂度分析 代码千千万,有些代码逻辑会很复杂,所以为了更细化的分析算法的复杂度,再复杂度分析方面引入了4个知识点: 1.最好情况时间复杂度(best case time complexity) ...

  6. 算法之如何进行算法复杂度分析

    一.什么是复杂度分析? 1.数据结构和算法解决是"如何让计算机更快时间.更省空间的解决问题". 2.因此需从执行时间和占用空间两个维度来评估数据结构和算法的性能. 3.分别用时间复 ...

  7. 怎么算matlab算法复杂度,算法复杂度分析

    1. 何为数据结构?何为算法? 简单来说,数据结构就是数据的存储方式,比如数组就是把数据存在一段连续的内存上,而链表则是通过指针的关联将数据存在任意可用的内存上:栈是先进后出,队列是先进先出. 而算法 ...

  8. 八大排序:Java实现八大排序及算法复杂度分析

    目录 QUESTION:八大排序:Java实现八大排序及算法复杂度分析 ANSWER: 一:冒泡排序 1.算法分析 2.时间复杂度分析 3.代码 二:选择排序 1.算法分析 2.时间复杂度分析 3.代 ...

  9. 网络流问题以及EK算法复杂度分析

    网络流问题以及EK算法复杂度分析 一.网络流算法 通过一个例子引入网络流问题. 现有一个自来水厂要往家里通水,自来水厂用Vs表示,家用Vt表示.从自来水厂到家之间连接了很多水管,并且中途经过很多转接点 ...

最新文章

  1. Asp.Net MVC4入门指南(3):添加一个视图
  2. Redis实现参数的集中式管理
  3. 数学:拓展中国剩余定理
  4. 英雄多少钱steam_¥50元到手蓝宝石显卡?玩转GTAV轻松CSGO英雄联盟帧数144fps
  5. 13行满分代码:1038 统计同成绩学生 (20分)
  6. redis常用命令_Redis的简介以及基本常用命令
  7. input内的字体颜色_嘉兴市硅胶喷涂颜色油订制
  8. 修改oracle默认日期,Oracle 修改默认日期格式
  9. 【2017年第1期】手机基站定位数据可视分析
  10. .net项目开发工具接口说明
  11. 《阿里感悟》- 技术人员的职业规划
  12. mysql 5.7.16 忘记root 密码 如何修改root密码
  13. Win7 IE8首页强制成http://www.2345.com/?uuc
  14. Linux 端口扫描
  15. 校招生入职半年多后担任社招面试官的体验
  16. [NOI Online 2021 入门组] 切蛋糕
  17. linux vi指令选则从某行到某行注释,详解linux vi命令用法
  18. 邮箱如何撤回已发送的邮件?
  19. Github连接不上问题
  20. 基因组选择的几个概念

热门文章

  1. mysql 碎片率_详解Mysql数据库表碎片计算公式、碎片整理方法,值得收藏
  2. IDAE中Modules, Facets 和 Artifacts 的作用及区别
  3. 解决服务器端口无法访问
  4. 分布式专题-分布式缓存技术之MongoDB01-应用场景及实现原理
  5. luogu1063:区间dp
  6. PromiseA+规范解读手写MyPromsie
  7. 智能工厂:数字化转型将给制造业带来哪些机遇? The Next Generation of Manufacturing: AI and Smart Factories
  8. Python实现人脸检测(个人、多人、视频)
  9. 电脑网络看不到其它计算机,怎么找不到共享电脑,详细教您局域网中共享电脑找不到怎么办...
  10. Flex4 css中skin设置报错解决