0%

开发实践

时间、空间复杂度不能跟性能划等号

在实际的软件开发中,复杂度不能与性能简单划等号,不能表示执行时间和内存消耗的确切数据量。

  • 复杂度不是执行时间和内存消耗的精确值
    在用大O表示法表示复杂度的时候,会忽略掉低阶、常数、系数,只保留高阶,并且它的度量单位是语句的执行频度。每条语句的执行时间,并非是相同、确定的。复杂度给出的只能是一个非精确度量值的趋势

  • 代码的执行时间有时不跟时间复杂度成正比
    对于小规模数据的处理,算法的执行效率并不一定跟时间复杂度成正比,有时还会跟复杂度成正比。

  • 对于处理不同问题的不同算法,其复杂度大小没有可比性
    复杂度只能用来表征不同算法,在处理同样的问题,以及同样数据类型的情况下的性能表现。对于不同的问题、不同的数据类型,不同算法之间的复杂度大小并没有可比性。

抛开数据规模谈数据结构和算法都是“耍流氓”

在数据规模很小的情况下,普通算法和高级算法之间的性能差距会非常小。如果代码执行频率不高,又不是核心代码,这个时候,选择数据结构和算法的主要依据是,其是否简单、容易维护、容易实现。大部分情况下,直接用最简单的存储结构和最暴力的算法就可以了。
小数据规模,对于处理时间是毫秒量级敏感的系统来说,高级算法的性能提升并不大,反而会陡增编码的难度,还容易产生bug。

结合数据特征和访问方式来选择数据结构

最考验能力的并不是数据结构和算法本身,而是对问题需求的挖掘、抽象、建模。如何将一个背景复杂、开放的问题,通过细致的观察、调研、假设,理清楚要处理数据的特征与访问方式,才是解决问题的重点。将问题转化成合理的数据结构模型,进而找到满足需求的算法。

区别对待IO密集、内存密集和计算密集

如果要处理的数据存储在磁盘,那代码的性能瓶颈有可能在磁盘IO,而非算法本身,需要合理的选择数据存储格式和存取方式,减少磁盘IO的次数。

数据存储在内存中,需要考虑代码时内存密集型的还是CPU密集型的。
CPU密集型,从内存中读取一次数据,到CPU缓存或者寄存器之后,会进行多次频繁的CPU计算,CPU计算耗时占大部分。在选择数据结构和算法的时候,要尽量减少逻辑计算的复杂度 ,用位运算道题加减乘除运算。
内存密集型,计算比较简单,每次从内存中读取数据之后,只需要进行一次简单的比较操作。内存数据的读取速度,是比较操作的瓶颈。在选择数据结构和算法的时候,要考虑是否能减少数据的读取量,数据是否在内存中连续存储,是否能利用CPU缓存预读。

善用语言提供的类,避免重复造轮子

对于大部分常用的数据结构和算法,编程语言都提供了现成的类和函数实现。Java中,HashMap—散列表;TreeMap—红黑树。

编程语言提供的类和函数,都是经过无数验证付的,不管是正确性、健壮性。

千万不要漫无目的地过度优化

对普通情况下的数据规模和性能压力做估算,同时对异常以及将来一段时间内,可能达到的数据规模和性能压力做估算。
优化代码时,先做基准测试,避免想当然的换了更高效的算法,但真实情况下,性能反倒下降。