算法的复杂度分析

本文是对极客时间《数据结构与算法之美》03-04 节课关于算法复杂度分析的小结。

前面:为什么要学习数据结构与算法

内容来自《数据结构与算法之美》01-02 节的内容,当我们需要做大量 coding 工作时,必要的数据结构和算法基础是非常重要的,写完一段代码,很多时候是需要去思考:这个数据结构设计得合理不合理?这段代码是否还有优化空间?是不是可以用个设计模式让代码架构显得更简洁清晰?这些思考的背后都是需要相应的基础做为支撑,如果这些基础比较薄弱的话,还是应该每周抽出个 2-3h 来去定向地提高自己,有了相应的工作经验之后再去复习这些基础,理解效果可能会更深刻一些(与大家共勉)。

对于业务开发同学来说,平时更多的是利用已经封装好的现成接口、类库来堆砌、翻译业务逻辑,很少需要自己实现数据结构和算法,但是不需要自己实现,并不代表什么都不需要了解

如果不了解其背后的原理,怎么能用好它们?出了问题怎么快速去定位问题?调用了某个函数之后,如何评估代码的性能和资源消耗呢?工作中,会用到各种框架、中间件和底层系统,在这些基础框架中,一般都糅合了很多基础数据结构和算法的设计思想

比如:我们常用的 key-value 数据库 Redis 中,里面的有序集合是用什么数据结构来实现的呢?为什么要用跳表来实现呢?为什么不用二叉树呢?

掌握数据结构和算法,不管对于阅读框架源码,还是理解其背后的设计思想,都是非常有用的。

对于基础架构的研发同学来说,写出达到开源水平的框架才是应该是我们的目标

现在互联网上的技术文章、架构分享、开源项目满天飞,照猫画虎做一套基础框架不是并不难。但不同做出的东西,差距非常大!
高手之间的竞争就在细节,这些细节包括:你用的算法是不是够优化,数据存取的效率够不够高,内存是不是够节省等等。这些累积起来,决定了一个框架是不是优秀。所以,如果你还不懂数据结构和算法,没听说过大 O 复杂度分析,不知道怎么分析代码的时间复杂度和空间复杂度,那肯定说不过去了。

掌握了数据结构和算法,看待问题的深度,解决问题的角度就会完全不一样。

为什么要复杂度分析?

数据结构和算法本身解决的是【快】和【省】的问题,即如何让代码运行得更快、如何让代码更省内存空间。因此,执行效率是算法一个非常重要的考量指标,那么如何进行衡量呢?那就是——时间、空间复杂度分析

复杂度分析是整个算法学习的精髓,只要掌握了它,数据结构和算法的内容基本上就掌握了一半

把代码运行起来,通过统计和监控也能得到算法执行的时间和占用的内存大小。那为什么还要时间、空间复杂度分析呢?这种分析方法能比我实实在在跑一遍得到的数据更准确么?

上面的评估方法是正确的,但它是事后统计法,这种方法的局限性很大:

  1. 测试结果非常依赖测试环境:比如不同的硬件环境的影响;
  2. 测试结果受数据规模的影响很大:比如,对于排序算法,待排序数据的有序度不一样排序的执行时间就会有很大差别。

因此,需要一个不用具体的测试数据来测试,就可以粗略地估计算法的执行效率的方法,这就是时间、空间复杂度分析。

O 复杂度分析法

一个算法的执行效率,简单来说,就是其算法的执行时间,如何从理论上进行分析呢?这就是这里要讲述的O 复杂度分析法

代码在运行时,从 CPU 的角度来说,其实都是读数据-运算-写数据,虽然每行代码执行时间并不一样(假设每行代码都是比较最简单的那种形式),但是在进行理论分析(粗略估计时),我们可以认为其是一样的,有了这个假设,那么:

一段代码的执行时间 T(n) 与每行代码的执行次数 n 成正比。

这里可以总结为一个公式:

T(n) = O(f(n))

这就是大 O 复杂度分析,其中:

  • T(n):代码的执行时间;
  • n:数据规模的大小;
  • f(n):每行代码执行的次数总和。

O 时间复杂度实际上并不具体代表代码真正的执行时间,而是表示代码执行随数据规模增长的变化趋势,所以,也叫做渐进时间复杂度(asymptotic time complexity),简称时间复杂度

时间复杂度分析

前面介绍了大 O 时间复杂度的由来和表示方法,这里来看下如何分析代码的时间复杂度,这里有三个常用的方法:

  1. 只关注循环执行次数最多的一段代码;
  2. 加法原则:总复杂度等于量级最大的那段代码的复杂度;
  3. 乘法原则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积。

对于这三点,对于接触过这块内容的同学,其实是很容易理解的,这里就不再详细介绍,这里看下几种常见的时间复杂度实例分析。

复杂度量级 —— 图片来自极客时间
时间复杂度跟 n 的关系——图片来自极客时间

O(1)

O(1) 并不是说代码执行一行,而是指代码执行了次数与 n 无关,比如下面代码的时间复杂度就是 O(1)

int a = 1;
int b = 2;
int c = a * b;

也就是说,只要代码不存在循环语句、递归语句,即使有成千上万行的代码,其时间复杂度也是 O(1)

O(logn)O(nlogn)

对数阶的时间复杂度很常见,但是比较难以分析,下面有个示例:

i = 1;
while (i <= n) {
    i = i * 2;
}

这段代码到底执行多少次,只需要把 2^k=n 中的 k 找出来就行了,而 k=log_2n,如果乘以的是 3,那么结果就是 k=log_3n,也就是说其时间复杂度是 O(log_2n)O(log_3n)

但是,由于 log_3n=log_32 * log_2n,所以不管是 O(log_2n)O(log_3n)O(log_10n),这里都会统一记为 O(logn)

O(nlogn) 的例子也类似。

O(m+n)O(m*n)

对于这种类型,其复杂度是由两个数据规模来决定的,常见的示例就是有两个循环,一个是循环 O(n) 次,一个是循环 O(m) 次。

空间复杂度分析

有了前面关于时间复杂度的分析,这里的空间复杂度也类似,空间复杂度的全称是渐进空间复杂度(asymptotic space complexity),表示算法的存储空间与数据规模之间的增长关系

常见的空间复杂度就是 O(1)O(n)O(n^2) 这种。

复杂度分析并不难、关键在于多练。

最好、最坏、平均、均摊时间复杂度

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

在分析时间复杂度时,很多情况下,其时间复杂度是有多种情况的,而为了表示在不同情况下的不同时间复杂度,这里引入了是三个概念:

  1. 最好情况时间复杂度:在最理想的情况下,执行这段代码的时间复杂度;
  2. 最坏情况时间复杂度:在最糟糕的情况下,执行这段代码的时间复杂度;
  3. 平均情况时间复杂度:这种情况,需要考虑各种情况出现的概念,也称作加权平均时间复杂度

一般来说,对于复杂度分析,这三种复杂度分析就足够了。

均摊时间复杂度

有种特殊的场景,其复杂度分析不需要像平均复杂度那样引入概率论去分析,而是引入了一个新的分析方法 —— 摊还分析法,分析的结果是均摊时间复杂度

它对应的场景是:在绝大多数情况下是低级别复杂度,只有在极少数情况下是高级别复杂度;低级别和高级别复杂度出现具有时序规律。

举个例子:假设前 n 个操作的复杂度都是 O(1),第 n+1 次操作的复杂度是 O(n),所以把最后一次的复杂度均摊到前 n 次上,那么均摊下来的每次操作复杂度为 O(1)

总结:均摊时间复杂度就是一种特殊的平均时间复杂度,这里应该关注是其分析方法、分析思想。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容