关注公众号 MageByte,设置星标点「在看」是我们创造好文的动力。后台回复 “加群” 进入技术交流群获更多技术成长。 本文来自 MageByte-青叶编写

上次我们说过 时间复杂度与空间复度,列举了一些分析技巧以及一些常见的复杂度分析比如 O(1)、O(logn)、O(n)、O(nlogn),今天会继续细化时间复杂度。

1. 最好情况时间复杂度(best case time complexity)

2.最坏情况时间复杂度(worst case time complexity)

3. 平均情况时间复杂度(average case time complexity)

4.均摊时间复杂度(amortized time complexity)

复杂度分析

public int findGirl(int[] girlArray, int number) {int i = 0;int pos = -1;int n = girlArray.lentgh();for (; i < n; ++i) {if (girlArray[i] == number) {pos = i;break;}}return pos;
}

代码逻辑你应该很容易看出来,在无序数组 中查找 number 出现的位置,如果没找到就返回 -1。《唐伯虎点秋香》主角星爷通过这个方法遍历数组找到秋香,因为此刻我们还没有学会各种风骚的算法,只能从头到尾查验是不是秋香,所以只能遍历数组。girlArray 数组保存着秋香、冬香、春香……的编码,现在唐伯虎通过 选择 number 这个编码比对是否是秋香。

这段代码在不同的情况下,时间复杂度是不一样的,所以为了描述代码在不同情况下的不同时间复杂度,我们引入了最好、最坏、平均时间复杂度。n = girlArray 数组的长度。

  1. 当如秋香在第一个,那 代码的时间复杂度就是 O(1)。
  2. 当秋香在队伍的最后一个,那代码的时间复杂度就是 O(n)。
  3. 当 秋香在队伍中但是不在队伍第一个,也不再最后一个,那么就不确定。
  4. 假如华府使诈,队伍里也根本不存在秋香,唐波徐也需要把队伍一个个查验完毕才知道,时间复杂度就成了 O(n)

最好情况时间复杂度

在最理想的情况下,执行这段代码的时间,也就是「唐伯虎」最快点中秋香。假如 这一排姑娘就代表 girlArray 数组,number 变量就是秋香的编码。假如第一个姑娘就是「秋香」那时间复杂度就是 O(1)。

最坏情况时间复杂度

在最糟糕的情况下,执行这段代码的时间复杂度。也就是要一个个查验真个数组的长度 O(n)。

平均情况时间复杂度

其实最好与最坏情况是极端情况,发生的概率并不大。所以为了更准确的表示平均情况下的时间复杂度,引入另一个改变:平均情况时间复杂度

还是上面的「找秋香」代码,判断 number 编码在循环中出现的位置,有 n + 1种情况:

在数组 0~n-1 中和不在这个数组中。在数组中共有 n 种情况,加上不在数组中则就是 n + 1 种了。 每种情况要遍历的姑娘人数都不同。我们把每种情况需要查找姑娘的数量累加,然后再除以 所有情况数量 (n + 1),就得到需要遍历次数的平均值。敲黑板了:公式就是平均情况复杂度 = 累加每种遍历的元素个数 / 所有的情况数量

平均情况复杂度为:

((1+2+3…+n)+n)(n+1)=n(n+3)2(n+1)\frac {((1+2+3… +n) + n)} {(n+1)} = \frac {n(n+3)} {2(n+1)}(n+1)((1+2+3…+n)+n)​=2(n+1)n(n+3)​

推导过程:

∵1+2+3…+n=n+(n−1)+(n−2)…+1\because 1+2+3 …+ n = n + (n-1) + (n-2)… + 1∵1+2+3…+n=n+(n−1)+(n−2)…+1

∴(1+2+3…+n)=n(1+n)2\therefore (1 +2 +3… + n) = \frac {n(1+n)} {2}∴(1+2+3…+n)=2n(1+n)​

∴(1+2+3+…+n)+n=n(3+n)2\therefore (1+2+3+…+n) + n = \frac {n(3+n)} {2}∴(1+2+3+…+n)+n=2n(3+n)​

根据我们之前学的 时间复杂度与空间复度 大 O 表示法,省略系数、地接、常量,所以平均情况时间复杂度是 O(n)

期望时间复杂度

上面的平均情况时间复杂度推导**没有考虑每种情况的发生概率,**这里的 n+1 种情况,每种情况发生的概率是不一样的,所以还要引入各自发生的概率再具体分析。

秋香的编号 number 要么在 0 ~ n-1 中,要么不在 0~n-1 中,所以他们的概率是 12\frac {1} {2}21​。

同时 number 在 0~n-1 各个位置的概率是一样的为 1/n。根据概率乘法法则,number 在 0~n-1 中任意位置的概率是 12n\frac {1} {2n}2n1​。

所以在前面推导的基础上,我们再把每种情况发生的概率考虑进去,那么平均情况时间复杂度的计算过程就是:

考虑概率的平均情况复杂度:

(112n+212n+312n…+nn2n)+n12=3n+14(1 \frac {1} {2n} + 2 \frac {1} {2n}+ 3 \frac {1} {2n}…+n\frac {n} {2n} ) + n \frac {1} {2} = \frac {3n+1} {4}(12n1​+22n1​+32n1​…+n2nn​)+n21​=43n+1​

这就是概率论中的加权平均值,也叫做期望值,所以平均时间复杂度全称叫:加权平均时间复杂度或者期望时间复杂度

引入概率之后,平均复杂度变为 O(3n+14\frac {3n+1} {4}43n+1​),忽略系数以及常量,最后得到的加权平均时间复杂度为 O(n)。终于分析推导完了,同学们可以松一口气。

注意:

多数情况下,我们不需要区分最好、最坏、平均情况时间复杂度。只有同一块代码在不同情况下时间复杂度有量级差距,我们才会区分 3 种情况,为的是更有效的描述代码的时间复杂度。

均摊情况时间复杂度

最后一个硬骨头来了,了解了上面加上概率的期望时间复杂度再看这个就容易多了。均摊时间复杂度,听起来跟平均时间复杂度有点儿像。

均摊复杂度是一个更加高级的概念,它是一种特殊的情况,应用的场景也更加特殊和有限。

对应的分析方式称为:摊还分析或平摊分析。

// array 表示一个长度为 n 的数组
// 代码中的 array.length 就等于 nint[] array = new int[n];int count = 0;public 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.lenth,遍历数组求和,将求和之后的 sum 值放到数组的第一个位置,然后再将新的数据插入。但如果数组一开始就有空闲空间,则直接将数据插入数组。这里的数据满:对于可反复读写的存储空间,使用者认为它是空的它就是空的。如果你定义清空是全部重写为 0 或者某个值,那也可以!使用者只关心要存的新值!

分析上述的时间复杂度:

  1. 最理想情况,有空闲空间则直接插入到数组下标 count 的位置即可。所以是 O(1)。
  2. 最坏的情况,数组没有空闲空间,需要先做一次循环遍历求和,然后再插入。时间复杂度 O(n)。

平均时间复杂度

数组长度为 n,因为可以插入不同位置,所以有 n 种情况,每种复杂度为 O(1)。

还有一种特殊情况,没有空闲空间插入的时候,复杂度是 O(n),一共就是 n+1 种情况,且每种情况的概率都是 1n+1\frac{1} {n+1}n+11​。所以根据加权平均计算法,平均时间复杂度:

(11n+1+11n+1+11n+1…+11n+1)+n1n+1=2nn+1(1 \frac {1} {n+1} + 1 \frac {1} {n+1}+ 1 \frac {1} {n+1}…+1\frac {1} {n+1} ) + n \frac {1} {n+1} = \frac {2n} {n+1}(1n+11​+1n+11​+1n+11​…+1n+11​)+nn+11​=n+12n​

当省略系数及常量后,平均时间复杂度为 O(1)。

其实我们不需要这么复杂,对比 findGirl 跟 insert 方法。

  1. findGirl 在极端情况下复杂度 O(1),而 insert 基本情况是 O(1)。只有当数组满了才是 O(n)。
  2. 对于 insert() 函数来说,O(1) 时间复杂度的插入和 O(n) 时间复杂度的插入,出现的频率是非常有规律的,而且有一定的前后时序关系,一般都是一个 O(n) 插入之后,紧跟着 n-1 个 O(1) 的插入操作,循环往复。

摊还分析法

分析上述示例的平均复杂度分析并不需要如此复杂,无需引入概率论的知识。

因为通过分析可以看出,上述示例代码复杂度大多数为 O(1),极端情况下复杂度才较高为 O(n)。同时复杂度遵循一定的规律,一般为 1 个 O(n),和 n 个 O(1)。针对这样一种特殊场景使用更简单的分析方法:摊还分析法

通过摊还分析法得到的时间复杂度为均摊时间复杂度

大致思路:每一次 O(n)都会跟着 n 次 O(1),所以把耗时多的复杂度均摊到耗时低的复杂度。得到的均摊时间复杂度为 O(1)。

应用场景:均摊时间复杂度和摊还分析应用场景较为特殊,对一个数据进行连续操作,大部分情况下时间复杂度都很低,只有个别情况下时间复杂度较高。而这组操作其存在前后连贯的时序关系。

这个时候我们将这一组操作放在一起分析,将高复杂度均摊到其余低复杂度上,所以一般均摊时间复杂度就等于最好情况时间复杂度。

注意: 均摊时间复杂度是一种特殊的平均复杂度(特殊应用场景下使用),掌握分析方式即可。

均摊时间复杂度就是一种特殊的平均时间复杂度,我们没必要花太多精力去区分它们。你最应该掌握的是它的分析方法,摊还分析。至于分析出来的结果是叫平均还是叫均摊,这只是个说法,并不重要。

文末思考

最后留一个问题给大家,用本文学习的只是分析下面代码的「最好」、「最坏」、「均摊」时间复杂度。

/ 全局变量,大小为 10 的数组 array,长度 len,下标 i。
int array[] = new int[10];
int len = 10;
int i = 0;// 往数组中添加一个元素
void add(int element) {if (i >= len) { // 数组空间不够了// 重新申请一个 2 倍大小的数组空间int new_array[] = new int[len*2];// 把原来 array 数组中的数据依次 copy 到 new_arrayfor (int j = 0; j < len; ++j) {new_array[j] = array[j];}// new_array 复制给 array,array 现在大小就是 2 倍 len 了array = new_array;len = 2 * len;}// 将 element 放到下标为 i 的位置,下标 i 加一array[i] = element;++i;
}

总体的含义就是向数组添加一个元素,当空间不够的时候重新生情一个原来两倍空间的数组并把原来的数组数据依次复制到新数组中。

其实同学们这里还可以拓展到 HashMap 的拓容,当元素大刀负载因子 0.75 的容量,HashMap 需要拓容为原来的两倍然后再重新 把元素放到新数组中。那么时间复杂度又是多少呢?

关注公众号 MageByte 后台回复 「add」获取本题目答案,也可以回复「加群」加入技术群跟我们一起分享你的看法,我们第一是时间反馈。

参考文献:《数据结构与算法之美》

3.最好、最坏、平均、均摊时间复杂度相关推荐

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

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

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

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

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

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

  4. 3L-最好、最坏、平均、均摊时间复杂度

    关注公众号 MageByte,设置星标点「在看」是我们创造好文的动力.后台回复 "加群" 进入技术交流群获更多技术成长. 本文来自 MageByte-青叶编写 上次我们说过 时间复 ...

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

    目录 最好.最坏时间复杂度 平均情况时间复杂度 均摊时间复杂度 小结 最好.最坏时间复杂度 我们先看一个例子: /*例1:查找x在数组中出现的位置,如果没有找到,返回-1.n表示数组array的长度 ...

  6. 最好、最坏、平均、均摊时间复杂度分析

    1.最好.最坏.平均情况时间复杂度 有时候我们分析一段代码的时间复杂度时,并不能很直观的就得出结果,需要结合具体的场合来判断它的平均情况.下面来看一个栗子: /*** 找出给定数组中给定元素的位置,如 ...

  7. 浅析最好、最坏、平均、均摊时间复杂度

    浅析最好.最坏.平均.均摊时间复杂度 下面讲解四个复杂度分析方面的知识点,最好情况时间复杂度(best case time complexity).最坏情况时间复杂度(worst case time ...

  8. 数据结构与算法---均摊时间复杂度

    数据结构与算法-均摊时间复杂度 均摊时间复杂度,听起来可能和平均时间复杂度.但却不是,平均时间复杂度和均摊时间复杂度是两种分析时间复杂度的方法. 上代码!!! // array 表示一个长度为 n 的 ...

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

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

最新文章

  1. JavaWeb项目第三次总结_成绩查询的实现
  2. 从入职快手3年股票3000w说起
  3. win10 nms cpu编译-ok
  4. 常用的 Http ContentType 对照表
  5. 页面添加锚点后如何点击不改变URL?
  6. python给字母赋值_给字母赋值的更快方法?
  7. linux 等待进程,Linux 进程等待队列
  8. error pulling image configuration: read tcp xxx.xxx.x.xxx:xx->xxx.xx.xxx.xx:xxx: read: connection
  9. 小程序预览报错60001,fail error:109
  10. 小布助手在面向中文短文本的实体链指比赛中的实践应用
  11. 图神经网络(一)DGL框架搭建GCN图卷积神经网络模型
  12. ASO优化:如何提高App Store应用商店中排名?
  13. 位运算——强大得令人害怕
  14. 爬虫实战——爬取小说《从你的全世界路过》
  15. “奇点”临近:2045,人类永生
  16. 电销接通率低,深圳外呼系统应该怎么选择?
  17. 家用电梯的曳引式电梯井道尺寸及配置
  18. VMware 安装Linux centOS 8
  19. 聊天室html布局,h5聊天室模板|仿微信聊天室html5
  20. 网站https前安全锁有感叹号的解决方法

热门文章

  1. mac地址和ip地址、子网掩码和默认网关
  2. 要是老大放手让你来做、你敢吗?
  3. 2022年上半年信息系统项目管理师上午综合知识真题与答案解析
  4. 多线程与并发编程入门基础,多图详解
  5. 苹果在macOS Big Sur 11.3中添加了新的屏幕保护程序——“Hello”
  6. [转载] 你真的知道什么是 Python“命名空间” 吗?
  7. 链上存储未来,CESS 如何促进 Web3 的大规模采用?
  8. Sinon教程:使用嘲弄,间谍和存根进行JavaScript测试
  9. ReiserFS是一个非常优秀的文件系统
  10. bionic linker代码分析(1) - linker自举