算法
算法就是解决一个实际问题的方法,反映在程序中就是为了解决一个问题的一系列代码。
如何炒西红柿;如何把大象装冰箱;如何遍历二叉树;如何毁灭地球?解决这些问题的方法都是算法。
算法设计要求
为了能够解决问题,算法是需要具备一些特点的。
算法特点
输入输出算法可有1个或0个输入,至少有一个输出。
输入是为了确立初始条件,也可以没有输入。
有穷性算法需要在有限的执行次数和执行时间下获得结果。确定性算法的每一步操作执行都应该是明确的。可行性算法的每个操作必须都是切实可行的。
算法评价
正确性算法是否获得了正确的结果。可读性算法可以被阅读理解的难易程度。
这一点经常被人忽视,但是是开发中最为重要的一环,是区分好坏程序员的重要标准,切记
不要写太过于聪明精巧的算法,需要考虑到维护迭代的成本,不然时过境迁自己都读不懂自己写的代码。
健壮性算法需要对异常情况的处理。
算法需要具备一定的容错性,最起码要对输入进行验证、提示。
时间效率执行算法需要消耗的时间资源。储存量低执行算法需要消耗的空间资源。
时间复杂度
时间复杂度,又称时间复杂性,算法的时间复杂度是一个函数,它定性描述该算法的运行时间。时间复杂度常用大O符号表述。
为了更好地描述时间复杂度有以下规定:
- 所有的常数时间复杂度用1表示。
- 只保留最高阶的时间复杂度。
- 去除最高阶时间复杂度的系数。
这样就得出了一个具体算法的时间复杂度,例如下:
算法时间复杂度为:1+(n+1)+n+1 = 3+2n -> O(n)
常见的时间复杂度
-
常数阶
-
线性阶
-
平方阶
-
对数阶
-
立方阶
-
nlog阶
-
指数阶 O(2^n) O(n!)
小结
关于各个时间复杂度的比较有下图所示:
时间复杂度描述的是算法的最坏情况。
空间复杂度
对于一个算法,所有的变量、指令、结果都需要存储空间,另外在算法的执行过程中,临时变量和临时结果也需要保留下来以便下一步计算,这些称为算法执行时的辅助空间。空间复杂度主要定性描述算法所需的辅助空间。
空间复杂度相对来说比较简单,只需要关注算法在执行时消耗的辅助空间即可,例如,
swap()函数中temp元素的消耗就是辅助空间。当然这个函数还能更高级,看大佬这里。
算法效率衡量
分析算法时,存在几种可能的考虑:
- 算法完成工作最少需要多少基本操作,即最优时间复杂度。
- 算法完成工作最多需要多少基本操作,即最坏时间复杂度。
- 算法完成工作平均需要多少基本操作,即平均时间复杂度。
对于最优时间复杂度,其价值不大,因为它没有提供什么有用信息,其反映的只是最乐观最理想的情况,没有参考价值。
对于最坏时间复杂度,提供了一种保证,表明算法在此种程度的基本操作中一定能完成工作。
对于平均时间复杂度,是对算法的一个全面评价,因此它完整全面的反映了这个算法的性质。但另一方面,这种衡量并没有保证,不是每个计算都能在这个基本操作内完成。而且,对于平均情况的计算,也会因为应用算法的实例分布可能并不均匀而难以计算。
因此,我们主要关注算法的最坏情况,亦即最坏时间复杂度。
一个好的算法如何测评?
答:作为程序员主要考虑的是算法的健壮性、可读性、时间效率、空间效率,这几个因素都很重要,需要兼顾。关于健壮性可以对算法的输入进行容错判断提示,对于边界值需要小心处理;关于可读性需要在算法的关键位置进行注释,对变量、方法的命名也要注意,还有一点,不是代码少就是好代码;关于时间复杂度和空间复杂度通常需要具体问题具体分析,这俩者之间有时也会因为业务互相取舍。