《数据结构和算法之美》学习笔记 Day 2

课程:《复杂度分析(上):如何分析、统计算法的执行效率和资源消耗?》 总结

算法的一个非常重要的的考量指标是执行效率复杂度分析就是用来衡量代码执行效率的一种方法。前面又提到复杂度分析是数据结果和算法学习的精髓

为什么需要复杂度分析?

1. 实际的测试结果非常依赖测试环境

比如测试环境硬件配置不一样,得到的结果截然不同

2. 测试结果受数据规模的影响很大

比如排序算法,就会受实际测试数据的有序度和数据的规模影响。导致测试的结果无法反应算法的性能。

3. 可以开发阶段更好的指导代码的编写

复杂度分析可以估算代码的执行效率,从而在根据实际选择算法时起到一定的指导作用。

复杂度分析不需要具体测试数据测试,就可以大概估计算法执行效率。既快速方便,又不受测试环境的影响,所以我们需要复杂度分析。

复杂度分析包括时间复杂度分析和空间复杂度分析,那么如何进行复杂度分析呢?

大O复杂度表示法

如果我们将每行代码的执行时间看成固定的,那所有代码的执行时间 T(n) 与每行代码的执行次数成正比。我们再将每行代码的执行次数之和用f (n)表示,那就可以总结出一个公式:

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

其中n表示数据规模的大小,O代表T(n)f(n)之间是正比关系。这就是大O时间复杂度表示法。

大O时间复杂度表示的是代码执行时间随数据规模增长的变化趋势并不是正真的执行时间。当n很大时,公式中的低阶、常量、系数三部分对变化趋势影响不大,所以可以忽略,只记录最大量级的那个就可以了。

时间复杂度分析

三个实用的时间复杂度分析方法:

1. 单一循环看次数执行最多的

2. 如果代码只受单一数据规模n的影响,非嵌套循环相加取量级最大的

3. 如果代码受多个数据规模的影响,非嵌套循环相加取和

4. 嵌套循环内外相乘取乘积

常见的时间复杂度有:O(1)、O(logn)、O(n)、O(nlogn)、O(n^2 )。

此外还有:O(m+n)、O(m*n),前者为复杂度有两个数据规模决定,后者则是起决定性的两个数据规模是嵌套的。

空间复杂度分析

由时间复杂度的表示意义可知,空间复杂度表示的是算法的存储空间随数据规模增长的变化趋势

常见的空间复杂度有: O(1)、O(n)、O(n^2 )。空间复杂度和时间复杂度类似,所以和数据规模n无关的相,我们都可以忽略。

时间复杂度练习:

练习一:

图一

如上图一:函数test,有一个形参n,这个函数需要执行的代码为第4行、第5行,在调用函数test的过程中,第4行n代码是将n5做了乘法,运行次数为1次,第5行代码为返回num的值,执行次数也为1次,根据大O复杂度表示法,可知f(n)为每行代码执行次数之和,所以这段代码的时间复杂度T(n)=O(1 + 1) = O(2),又因为时间复杂度研究的是代码执行时间随数据规模增长的趋势。可见,图一代码中每行代码的执行次数之和是一个常量,当n很大时,常量对变化趋势影响不大,所以可以忽略。这种代码执行时间为常量的时间复杂度都可以表示为O(1)。

图二
图三

再看图二、图三,虽然代码的行数变多了,但是通过分析可知,这几段代码中每行代码的执行次数之和都是常量,执行时间并不随数据规模n的增长而变化。所以他们的时间复杂度都是O(1)

一般情况下,只要算法中不存在循环语句、递归语句,即使有成千上万行的代码,其时间复杂度也是O(1)

练习二:

图四

再看图四,分析可知第4行代码的执行次数是n次,第5行代码的执行次数也是n次,可得这段代码的时间复杂度T(n)=O(n + n)=O(2n)。我们将系数忽略,取最大两级的一个,得到T(n)=O(n)。所以这段代码的时间复杂度就是O(n)。这也验证了“单一循环看次数执行最多的行”的分析方法。

练习三:

图五

再来看一个嵌套循环,如图五,分析可知第4行代码执行次数为n,第5行代码执行次数为n x n,第6行代码的执行次数为n x n。所以根据大O复杂度表示法可得这段代码的时间复杂度为:T(n)=O(n + nxn + nxn)=O(n+2n^2 )。又知低阶、系数可以忽略,这段代码的时间复杂度为:T(n)=O(n^2 )。刚好验证了“嵌套循环内外相乘取乘积”的分析方法。

练习四:

图六

如图六,根据单一循环看次数执行最多的行的分析方法,可知我们只要分析第5行代码或者第6行代码就可以了。代码中循环结束的条件是i>=n,但是i并不是每次递增1,i的变化是每次乘以2。假设第6行代码执行x次后循环结束,那么i的取值列出来就是, , , , ,2^5 ,...,可以看出i的值为,x即为第6行代码执行的次数。也就是当2^x >= n时循环结束。那我们就可以近似的得出第6行代码的执行次数x=\log_2 n 所以这段代码的时间复杂度T(n)=O(\log_2 n )。那么当第6行代码变成i= i * 3或者i=i*10等的时候,那这段代码的时间复杂度就是O(\log_3 n )O(\lg n )。不管是以哪个数字为底,我们都可以把这种对数阶的时间复杂度表示为O(logn)。所以图六代码的时间复杂度为T(n)=O(logn)。

练习五:

图7

我们已经知道test函数这段代码的时间复杂度为O(logn),那test2这段代码是将test代码段嵌套在了一个for循环中,根据“嵌套循环内外相乘取乘积”的分析方法,可知for循环test函数的执行次数为n,所以外部循环代码段的时间复杂度为O(n),又因为内部循环代码段的时间复杂度,也就是test代码段的时间复杂度为:O(logn),可得到test2代码段的时间复杂度T(n)=O(n)*O(logn)=O(nlogn)。

练习六:

图8

前面的代码段都是只有一个参数n,图8中的test函数有两个形参mn,再看函数体,第3、4行代码的执行次数受m的影响,第5、6行代码的执行次数受n的影响。即图8代码段的每行代码的执行次数之和受到了mn两个数据规模的影响。这种情况下,mn都不能确定是多少,所以都不能忽略。我们分析可知,第3、4行代码的时间复杂度T1(m)=O(m),第5、6行代码的时间复杂度T2(n)=O(n),所以根据“如果代码受多个数据规模的影响,非嵌套循环相加取和”的分析方法可得,这段代码的时间复杂度为:T(m)+T(n)=O(m)+O(n)=O(m+n)

练习七:

图9

图9代码段是一个嵌套循环,我们可以先将第4、5行代码段看成是一个单一循环,很容易可以得到它的时间复杂度T(n)=O(n),再看第3行代码,这是外部循环部分,这行代码的执行次数受m的影响,从而得到外部循环代码段的时间复杂度为T(m)=O(m),根据“嵌套循环内外相乘取乘积”的分析方法,可得test代码段的时间复杂度为:T(m)*T(n)=O(m)*O(n)=O(m*n)

空间复杂度练习:

练习一:

图10

图10中,第3行代码中,我们申请了一块空间a来存放数字4,第4行代码中我们又申请了一块空间sum来存放a+n的和。第5行代码并没有申请空间,只是返回了sum的值。由于空间复杂度表示的是算法的存储空间随数据规模增长的变化趋势,而经过我们分析,不管n的数据规模如何变化,这段代码永远只是申请了asum两块空间,并没有对存储空的的变化趋势造成影响,可见是常量阶的,所以这段代码的空间复杂度为:O(1)

图11

再来看图11,第3行代码中创建了一个list对象num_list,第4、5行代码中是循环三次,每次讲i*n的值存放到num_list对象中。由于num_list是一个可变对象,每存入一个数据就需要申请一块存储空间。但是由于第4行代码中,循环的次数是固定的3次,所以不管数据规模n如何变化,代码中只是申请了三次存储空间。也没有对存储空间的变化趋势造成影响,所以它的空间复杂度也是常量阶的,所以也是O(1)

练习二:

图12

图12和图11不同之处在于第4、5行代码的执行次数受n的数据规模的影响,我们知道num_list对象是一个列表,每放入一个数据都会申请一块空间存储,如果放入n个数据,那就要申请n块空间存储,所以这段代码的申请存储空间的次数或总量,会受到n的影响,所以可以得出这段代码的空间复杂度为:O(n)

图13

图13是在图12代码段的举出上又嵌套的一层循环,更具“嵌套循环内外相乘取乘积”的分析方法,可知,图13这段代码的空间复杂度为:O(n*n)=O(n^2 )

以上就是我对本节课程的理解,当然例子都是写的简单的例子。王争老师提到“复杂度分析并不难,关键在于多练。”,我在学习的时候,就是先听讲几遍,在动手写一下代码,试着分析一下复杂度。然后再和课程讲的核对下,看是不是一样,然后再多听几遍。这样使我印象更深刻。慢是慢了些,但相信对我而言应该是不错的学习方法。

以上可能有些理解的不到位,或是表达的不准,欢迎大家指正,帮助我更好的理解。



上一篇:《数据结构和算法之美》学习笔记 Day 1

下一篇:《数据结构和算法之美》学习笔记 Day 3

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

推荐阅读更多精彩内容