数据结构与算法之美-复杂度分析-极客时间笔记

数据结构和算法结构是代码世界的基础,我们通常使用的工具包/函数库都是将复杂操作包装起来只留出接口给我们调用。但如果想用的明明白白,还是要自己学会不同的数据结构的特点以及如何设计算法。

程序的性能无非是通过“快”和“省”来体现,也就是运行速度和存储空间,实现相同功能的代码之间也可能存在天差地别,我们不能仅仅是写能用的代码,而是好代码。

对比代码的性能,首先想到的就是以实际运行环境来跑一遍测试(事后统计法),但这种方法会依赖测试机器和测试数据规模,能分析一定的问题,但针对某些运行时间很长,或者难以重现效果的情况,我们还是需要引入理论性的分析方法:复杂度分析。

复杂度分析就是一种“纸上谈兵”式的估算算法效率的方法,针对运行速度和存储空间分为时间复杂度和空间复杂度。


时间复杂度

虽然通过汇编语言,我们知道不同的操作语句,其实会对应不同的计算机执行时间,比如加与乘。但在时间复杂度分析中,我们统一将所有基本语句的执行时间都估算为一致的,这样就通过代码执行次数与运算时间联系起来。也就是代码块中需要运行多少行,是否存在循环,循环次数如何。

进一步,时间复杂度是评估代码执行时间随数据规模增长的变化趋势(也叫作渐进时间复杂度)。所以时间复杂度公式中的低阶、常量、系数就可以忽略不计,只保留随数据规格变化最大的一项。

常见的复杂度量级分类如下:左侧为多项式量级,右侧为非多项式量级(效率随数据增加而激增),从上到下,时间复杂度逐渐增大。主要常见的还是多项式量级的,单独说下对数复杂度,常见于while循环,对被循环操作数进行等比变化,这样循环的实际次数就和数据规格成对数关系。而对数运算的特性,无论对数的底是多少,都可以通过系数变成统一的对数底,而系数在复杂度分析中忽略不计,这样这类复杂度就统称为对数阶时间复杂度。

时间复杂度深究下去,还可以根据数据的情况划分为最好情况时间复杂度/最坏情况时间复杂度。最常见的就是排序的情况,数据可能是原本就全部有序,也可能是完全无序。这样排序算法中通过高有序度来提前结束循环就是最好情况,而因为有序度低而把循环一直执行到退出则是最坏情况。

实际中操作数据的情况并不靠我们掌控,所以不能单独的看最好情况或最坏情况,而是综合考虑所有情况。平均情况时间复杂度是按照概率分布来计算每种情况发生的概率及每种情况下的时间复杂度。均摊时间复杂度则是针对某些特殊情况下才会执行的代码时间,将额外增加的时间均摊到其他常规的代码执行时间上去。比如数组指针到尾部后到数组迁移这些特殊情况。一般这种高时间复杂度的操作出现次数远低于一般情况,这样可以将增加的这部分时间均摊到每次的常规级操作,所以均摊时间复杂度一般就等于最好情况时间复杂度。

时间复杂度分析方法:

1、只关注循环执行次数最多的一段代码。因为除了与数据规模相关的循环,其他代码和数据规格都没有关系,都是固定执行次数,所以不会改变(渐进)时间复杂度。

2、加法法则:总复杂度等于量级最大的那段代码的复杂度,有对比才有伤害,在高复杂度面前,低阶复杂度往往都因为量级缘故而被忽视。如果算法复杂度涉及到多个数据规格,那么加法法则则并不适应,因为实际运行时间是两个变量,数据规模和时间复杂度。低复杂度的代码块配上更大规模的数据同样会造成运行时间激增。

3、乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积。嵌套的概念,子程序块对于外部程序块只是一条特殊语句,所以在复杂度上等于外部程序块的复杂度乘以子程序块的复杂度。


空间复杂度

表示算法的存储空间与数据规模之间的增长关系,就是指为了执行该算法,额外申请了多少空间。比如数组复制或者排序操作中需要额外申请等长的一个空间用于保存中间变量或者为了不修改原始数组等情况。


时间与空间是矛盾体,难以兼得。为了算法运算更加快捷,我们会使用更多的存储空间来进行更多“骚”操作。但如果限制存储空间,那就是螺蛳壳里做道场,不能强求速度。所以算法选择并没有两全法,看具体场景是哪种性能更重要或者哪种资源更加受限。

当内存空间充足的时候,如果我们更加追求代码的执行速度,我们就可以选择空间复杂度相对较高、但时间复杂度相对很低的算法或者数据结构。相反,如果内存比较紧缺,比如代码跑在手机或者单片机上,这个时候,就要反过来用时间换空间的设计思路。优化的努力方向也是类似,对于执行较慢的程序,可以通过消耗更多的内存(空间换时间)来进行优化;而消耗过多内存的程序,可以通过消耗更多的时间(时间换空间)来降低内存的消耗。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值