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

上一篇文章学习了:如何分析、统计算法的执行效率和资源消耗? 点击链接查看上一篇文章:复杂度分析上

今天的文章学习以下内容:

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

1、最好与最坏情况时间复杂度

我们首先来看一段代码,利用上一篇文章学习的知识看看能否分析出它的时间复杂度。

// n 表示数组 array 的长度
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;}}return pos;
}

这段代码很简单:就是在一个数组中找到一个数X的下标,将其返回。

利用上一篇文章学习的大O表示法来分析时间复杂度的话,有一些问题。if循环中有一个breadk语句,当条件成立,得到下标值立马退出循环。那么时间复杂度,就不能笼统的说是O(n)。

因为当想要查找的数就在第一个位置时,时间复杂度实际上是O(1),当想要查找的数在最后一个位置的时候,时间复杂度是O(n)。那么这个时候,我们就需要引入几个新名词:最好情况时间复杂度,最坏情况时间复杂度。

很容易理解。

  • 最好情况时间复杂度就是在最理想的情况下,执行代码需要的时间复杂度。就像上述代码,如果想要查找的数就是数组中的第一个位置,那么时间复杂度就是O(1),此时就是最好情况时间复杂度。
  • 最坏情况时间复杂度是在最不理想的情况下,执行代码需要的时间复杂度。还是如上述代码,入股我们想要查找的数在数组的最后一个位置,那么时间复杂度就是O(n),此时就是最坏情况时间复杂度。

其实还有一种情况,就是我们想要查找的数不在第一个位置也不在最后一个位置的时候。此时的时间复杂度是多少呢?这种情况下叫做平均情况时间复杂度

那么平均情况时间复杂度如何计算?它是多少呢?

2、平均情况时间复杂度

还是拿上面的代码做例子。

想要计算出它的平均情况时间复杂度,有两种方法,一种不严谨的感官上的方法,一种严格的概率上的方法。

  1. 不严谨的感官上的方法

我们知道,想要查找的数据x有两种情况的存在,一种是存在数组的0~n-1的某一个位置(n种可能),一种是不在这个数组中(1中可能,就是不在数组中)。这两种情况一共有n+1种可能。对于在数组中的n中可能中,每一种查找的次数分别是1,2,3,4…n。对于不在数组中的这种可能,查找次数是n。所以可以这么计算平均情况时间复杂度:

(1+2+3+...+n+n)/(n+1)=n(n+3)/2(n+1)

上一篇文章我们知道,利用大O表示法,,可以将计算结果的系数,低阶,常量去掉。那么上述的结果就是O(n)。

为什么说他不严谨呢?考虑以下情况。要找的数x存在于数组中与不存在于数组中的概率是否一样?x存在的话。它存在于数组中每个位置的概率是否一样?

很明显,上述方法没有考虑概率的问题。

  1. 概率的方法

现在假设,x出现在数组中与不出现在数组中的概率是相等的,都是1/2.同时假设x如果出现在数组中,则它存在数组中的每一个位置的概率都是一样的1/n。那么可以用如下方法计算平均情况时间复杂度。

(1×1n×12+2×1n×12+3×1n×12+...+n×1n×12+n×12)=3n+14(1 \times \frac{1}{n} \times \frac{1}{2}+2 \times \frac{1}{n} \times \frac{1}{2} +3 \times \frac{1}{n} \times \frac{1}{2} +...+n \times \frac{1}{n} \times \frac{1}{2} + n \times \frac{1}{2})= \frac{3n+1}{4}1×n1×21+2×n1×21+3×n1×21+...+n×n1×21+n×21=43n+1

利用大O表示法来表示的话,依然是O(n)。这就是上面那段代码的平均情况时间复杂度。

一般情况下,我们只是用其中一种复杂度来分析问题就够了,不需要费力去求解三种时间复杂度。只有在时间复杂度有量级的差距时,才会在不同的情况下使用不同的时间复杂度。

3、均摊时间复杂度

上面学会了最好最坏与平均时间复杂度。还有一种时间复杂度叫做均摊时间复杂度。 为了理解均摊时间复杂度,我们先来看一个代码:

 // array 表示一个长度为 n 的数组// 代码中的 array.length 就等于 nint[] 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从末尾挪到第二个位置,就可以认为是清空数组)。

利用上述的分析,我们可以求得:

  • 最好情况时间复杂度:O(1),因为数组不满的时候直接插入,不用计算和。
  • 最坏情况时间复杂度:O(n),因为此时数组满了,需要遍历一遍数组然后求和。

平均时间复杂度,还可以利用上述的概率分析法来计算。假设数组长度是n,往数组插入数据会有两种情况发生。数组没满时,插入的时间复杂度是O(1),且插入的位置有n种可能。数组满时,插入的时间复杂度是O(n),插入的位置只有一种可能。所以一共有n+1种可能插入的位置,且插入到它们位置的概率是一样的都是1/(n+1)。所以可以利用下面的方法计算平均情况时间复杂度:
(1×1n+1+2×1n+1+3×1n+1+...+n×1n+1+n×1n+1)=O(1)(1 \times \frac{1}{n+1}+2 \times \frac{1}{n+1} +3 \times \frac{1}{n+1} +...+n \times \frac{1}{n+1} + n \times \frac{1}{n+1})= O(1)1×n+11+2×n+11+3×n+11+...+n×n+11+n×n+11=O1

所以

  • 平均情况时间复杂度:O(1)

上述计算平均时间复杂度的方法,不管怎么样,还是有一些复杂。毕竟我们不是研究数学的。所以还是希望尽可能简单。

针对上面的两个代码例子,一个是find函数,一个是insert函数。看看他们有什么不同。find函数是最极端的情况下时间复杂度是O(1),大多数的情况下时间复杂度是O(n),而insert函数是大多数情况下的时间复杂度是O(1),只有极端的情况下时间复杂度是O(n)。

而且,对于insert函数,它的O(1)出现的是连续出现多次,然后出现一次O(n)时间复杂度。这具有一种时序关系。

针对这种情况,给出一种特殊的时间复杂度分析方法,均摊时间复杂度。可以通过摊还分析法,的带均摊时间复杂度。那么针对insert函数,如何通过摊还分析法来得到均摊时间复杂度呢?

首先,对于insert函数,大多是出现O(1)时间复杂度的,一共出现n次O(1)时间复杂度后,才出现一次O(n)时间复杂度。虽然O(n)时间复杂度消耗的时间比较多,但是O(1)时间复杂度出现的次数多,我们可以将O(n)消耗的时间,均摊给其他n个O(1)时间复杂度操作上的话,对于O(1)时间复杂度,也并不会有多大的影响,就好比,100个人共同抬100斤水泥,而另外又有一个人在抬100斤水泥,如果这个人把水泥平均分给那100人,那100人也才每个人多抬了一斤的水泥,这相比让那一个人抬100斤水泥,简直不要太轻松!!!。 所以,对于insert函数均摊时间复杂度为O(1)。这等于大多数情况下的时间复杂度。

综上:

  • 均摊时间复杂度为:O(1)

由以上的分析,我们得出,大概在以下情况下可以使用摊还分析来分析均摊时间复杂度

对一个数据结构进行连续的操作,如果大多数情况下的时间复杂度比较低,只有极端情况下时间复杂度很高,而且这些操作在时序上存在前后连贯的关系。那么此时,就可以将比较耗时的那个操作,均摊给大多数低的时间复杂度的操作上。

而且,一般可以用均摊时间复杂度分析的情况,均摊时间复杂度就等于最好情况时间复杂度

4、总结

上面学习了四种时间复杂度的分析。但是一般来说,平均时间复杂度用的很少,均摊时间复杂度用的就更少。而且,均摊时间复杂度,实际上是一种特殊的平均时间复杂度。

所以不必纠结到底用什么复杂度来分析问题,根据实际问题需要实际分析。对于一段代码,如果它的时间复杂度在不同情况下量级不同,可以采用不同的方法进行对比分析。其中最好最坏时间复杂度比较好分析,平均时间复杂度与均摊时间复杂度比较难分析。

但是对于平均和均摊。他们实际是一个意思,都有平均的意思。当出现O(1)操作的多于O(n)操作的时候,平均和均摊时间复杂度就都是O(1)。 这是一种感觉。一般情况下,我们都可以感觉对,而不用实际的计算。

本文是自己学习极客时间专栏-数据结构与算法之美后的笔记总结。如有侵权请联系我删除文章。

学习探讨加个人(免费送技术书籍PDF电子书):
qq:1126137994
微信:liu1126137994

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/423047.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【软件开发底层知识修炼】六 Binutils辅助工具之- addr2line与strip工具

学习交流加 个人qq&#xff1a; 1126137994个人微信&#xff1a; liu1126137994学习交流资源分享qq群&#xff1a; 962535112 上一篇文章我们学习了gcc编译器的相关内容。点击查看上一篇文章&#xff1a;gcc编译器。本篇文章接着上一篇文章&#xff0c;学习GNU为GCC提供的辅助开…

Eboot 中给nandflash分区实现

提到分区就不得不提到MBR&#xff0c;不得不提到分区表。 什么是MBR 硬盘的0柱面、0磁头、1扇区称为主引导扇区&#xff0c;NANDFLASH由BLOCK和Sector组成&#xff0c;所以NANDFLASH的第0 BLOCK&#xff0c;第1 Sector为主引导扇区&#xff0c;FDISK程序写到该扇区的内容称为主…

kmp匹配算法

kmp匹配算法1.第一种方式是暴利匹配方式2.第二种方式采用kmp 方式进行匹配3. 相应的代码1.第一种方式是暴利匹配方式 暴利匹配规则 模型: str1 位源字符串下标为i&#xff0c;str2位匹配字符串,下标为j 。 假设 str1 匹配到i , str2 匹配到j 则有 &#xff08;1&#xff09;当 …

四维空间和五维空间N维空间遐想

四维空间和五维空间遐想1. 二维空间2. 三维空间3.四维空间5.五维空间就类一个球体1. 二维空间 二维空间是&#xff0c;一个平面 例如 x轴y轴&#xff1b; 2. 三维空间 三维空间是&#xff0c;是一个立体&#xff0c;可以简单理解为 x轴&#xff0c;y轴&#xff0c; z轴 易可理解…

【软件开发底层知识修炼】七 Binutils辅助工具之- ar工具与nm工具

学习交流加 个人qq&#xff1a; 1126137994个人微信&#xff1a; liu1126137994学习交流资源分享qq群&#xff1a; 962535112 上一篇文章学习addr2line与strip工具。点击链接查看上一篇文章&#xff1a;点击查看 本篇文章学习两个工具&#xff1a;ar与nm工具。 文章目录1、ar工…

【软件开发底层知识修炼】八 Binutils辅助工具之- objdump工具 与 size,strings工具

上一篇文章学习了ar工具与nm工具&#xff0c;点击链接查看上一篇文章&#xff1a;点击链接 本片文章学习记录以下三个工具: objdumpsizestrings 1、objdump工具 用法&#xff1a; 反汇编目标文件&#xff0c;查看汇编到源码的映射&#xff08;后面代码案例分析看具体区别&a…

兼容门:先卸载腾讯QQ,再卸载360软件!

腾讯&#xff0c;360&#xff1a; 你们好&#xff0c;鉴于目前低级趣味的中国互联网兼容门事件愈演愈烈&#xff0c;让我的电脑感到消化不良&#xff0c;非常的痛苦不安。 为了心爱的电脑的健康和安全着想&#xff0c;我刚刚作出了一个艰难的决定&#xff1a; 卸载腾讯QQ系列软…

【C++深度剖析教程39】实现C++数组类模板

上一篇文章在那个学习了多参数类模板与特化的分析&#xff1a;点击链接查看上一篇文章&#xff1a;类模板深度剖析 本篇文章学习记录&#xff1a; 数值型模板参数实现C数组类模板 1、模板中的数值型参数 模板参数可以是数值型参数。也就是非类型参数。如下图所示&#xff1…

前端学习(168)全局事件属性

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/ TR/html4/strict.dtd"> <html><head><meta http-equiv"content-type" content"text/html; charsetutf-8"><title>事件</ti…

【原】两个时间相加的运算符重载实现

要求&#xff1a;两个时间相加&#xff0c;得到的时间形如“xx时&#xff1a;xx分&#xff1a;xx秒” -------------------------------------------------------------------------------------------------------------- 解答&#xff1a; 首先编写时间处理类 时间类 1 ///&l…

IOT变现

IOT&#xff08;物联网&#xff09;变现1. IOT 设备基础结构2.IOT 组成元素3.从M2M扩展到IOT的世界4. 工业4.0最近在看IOT变现&#xff0c;记录一下核心的知识点概念&#xff1a;IOT 是利用无线标签&#xff0c;传感器&#xff0c;MEMS(micro-ElectroMechanical System&#xf…

【C++深度剖析教程40】使用数值型模板技术计算1+2+3+...+N的值

上一篇文章学习了数值型模板技术&#xff0c;并利用相关技术&#xff0c;实现了C的数组类模板。点击文章查看上一篇文章&#xff1a;点击链接查看 本篇文章&#xff0c;继续利用模板技术来解决一个问题。 如果想求123…N的结果&#xff0c;有很多种方法。可以循环遍历&#x…

前端学习(169):无语义元素

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/ html4/strict.dtd"> <html><head><meta http-equiv"content-type" content"text/html; charsetutf-8"><title>无语义标签&…

dubbo思维导图

dubbo思维导图之前总结的 后续持续更新中

apache下django配置【原创】

在http.conf中加入<Location "/mysite/"> SetHandler python-program PythonHandler django.core.handlers.modpython SetEnv DJANGO_SETTINGS_MODULE settings PythonOption django.root /mysite PythonDebug On PythonPath "[/srv/ww…

前端学习(170):无语义元素二

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/ html4/strict.dtd"> <html><head><meta http-equiv"content-type" content"text/html; charsetutf-8"><title>DIVCSS布局&…

【软件开发底层知识修炼】九 链接器-可重定位文件与可执行文件

上几篇文章学习了Binutils辅助工具里面的几个实用的工具&#xff0c;那些工具对于以后的学习都是非常有帮助的&#xff0c;尤其是C语、C语言的学习以及调试是非常有帮助的。点击链接查看上一篇文章&#xff1a;点击查看 本篇文章开始一个新的知识的学习&#xff0c;链接器的学习…

【软件开发底层知识修炼】十 链接器-main函数不是第一个被执行的函数

上一篇文章&#xff0c;大概了解了链接器的工作内容就是&#xff1a;符号解析和重定位。点击上一篇文章查看&#xff1a;点击查看。 本片文章其实还是围绕链接器来学习。只不过不是很明显&#xff0c;当你学到下一篇文章时&#xff0c;就明白了。 本篇文章来弄明白一个问题&a…

分享博文摘要图标【11/16更新】

经常写文章&#xff0c;希望给朴素的浏览界面添加一些生动的图标&#xff0c;让浏览者直接通过图片来得知这篇文章讲的是什么&#xff1f; &#xff08;效果预览...&#xff09; 博主特意搜集并上传了一些大家可能会用到的图标&#xff0c;提供16、32、48、64、128、甚至256像素…

前端学习(171):注释元素

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/ html4/strict.dtd"> <html><head><meta http-equiv"content-type" content"text/html; charsetutf-8"><title>注释</ti…