什么是算法?
引用百度百科的一段话:算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。如果一个算法有缺陷,或不适合于某个问题,执行这个算法将不会解决这个问题。不同的算法可能用不同的时间、空间或效率来完成同样的任务。一个算法的优劣可以用空间复杂度与时间复杂度来衡量。
在Java中,我是这样理解的。首先算法,需要解决某个描述性的问题。那么这个问题可大可小,大到满足产品特征性业务需求,小到简单的数据输入输出。
比如我需要对某一个样本数据进行排序,那么首先最原始的算法就是把所有的数都比较一遍,那么从时间复杂度来说效率肯定很低,如果这时候就有一个效率较高的算法来进行排序,并且输出结果与最原始的结果又完全正确,那么对于当前这个样本数据我肯定选择无限接近最优的算法。
在Java中,数据结构又会决定算法的适用场景,还需要根据时间复杂度,空间复杂度来择优算法。说了这些,本质是为了提高数据的产出效率。那么效率提现在哪呢?别急,下面会根据应用场景举例说明。
那么评估算法优劣的核心指标是什么?
- 时间复杂度
- 额外空间复杂度
- 常数项时间
算法中常见的名词
时间复杂度
首先我们先抛开那些专业的理论。想象一下,当我们要计算数据样本量很大的时候,一昧的去计算每个细节计算的复杂度,那估计得算到恒星陨落去了。所以我们只看最高阶项那么就知道最坏的情况是多少时间复杂度了。举个例子,某两个时间复杂度计算公式为:
T(n) = an² + bn+c 或 T(n) = xn + yn + zn²
那么这两个公式的最高阶项都为n²,那么时间复杂度就是O(n²),这时候你就有疑问了,那我n都是常数1呢?这种情况就是时间复杂度最好的情况了,就不能用O(n²) 来衡量这个公式的复杂度了,但是这个公式始终也可能存在最坏的情况,不是常数1,那么用O(n²)来表示这个公式的时间复杂度就完全没问题了。所以决定某个算法的时间复杂度,与数据样本量有关系,和计算时间频度无关,即使是两个不同时间频度的公式,但时间复杂度也存在相同的情况。
我相信在各种博客都会聊到:
在各种不同算法中,若算法中语句执行次数为一个常数,则时间复杂度为O(1)。
按数量级递增排列,常见的时间复杂度有:常数阶O(1),对数阶O(log2n),线性阶O(n),线性对数阶O(nlog2n),平方阶O(n2),立方阶O(n3),…,
k次方阶O(nk),指数阶O(2n)。随着问题规模n的不断增大,上述时间复杂度不断增大,算法的执行效率越低。
关于这个理论实在是太长篇大论了,所以你只需要记住,只看最后计算公式的最高阶项,那么就是它的时间复杂度!
额外空间复杂度
实现一个算法,在实现算法的过程中,你需要开辟一些新的空间来支持你的算法,这就是额外空间。需要注意的是:
- 作为输入参数的空间,不算额外空间。
- 作为输出结果的空间,也不算额外空间。
因为实现算法过程中这些都是必要的,和实现目标有关。如果你的实现过程还需要开辟空间才能完全实现算法的流程,那么这就是额外空间。
如果你的额外空间就是几个临时变量,那么就是常数级别的操作,O(1)。如果你申请了一个与算法输入参数相同的空间,那么就是O(N)。
对数器
对算法准确性的校验。比如我们写了一个算法A,但是你一些简单的数据样本测试通过了,但是用复杂的数据样本测试的时候却报错了,但是又不知道错在哪,怎么办?
- 实现一个时间复杂度效率较低的算法B,或者使用现成的算法API
- 实现一个随机数据样本生成器
- 使用相同的随机样本数据进行测试算法A和B,然后比较结果
- 如果算法AB在某个随机样本下的结果不一致,则调试算法A,进行优化。
- 优化完成后,算法A和B的结果不管随机多少数据样本都一样,那么可以确定这个算法A是正确的
常数项时间
引用百度百科的一段话:在计算复杂度理论中,常数时间是一种时间复杂度,它表示某个算法求出解答的时间在固定范围内,而不依照问题输入数据大小变化。常数时间记为O(1)(采用大O符号)。数字1可以替换为任意常数。
个人理解常数时间复杂度,在Java中是一些不因为数据量样本大小,而对数据操作为固定时间的算法操作就是常数级别的。比如以下例子:
-
数组寻址操作。比如想在 “访问数组上的元素” 的问题上达到常量时间,只要以元素的下标(index)访问即可。然而 “在数组上搜索最小值” 并不是一个常量时间问题,因为这需要扫描数组上的每一个元素以寻找最小值及其位置,一般需要O(n)次访问。
-
常见的算术运算(+、-、*、/、%)
-
常见的一些二进制计算(位移、异同或)
-
常见的 “值” 运算(赋值、比较、自增、自递减)
为什么自己写算法?
- 算法与程序语言无关。
- 程序语言具备的api无法满足需求时,需要手动改写。
- 软件工具的底层依赖最基本的算法和数据结构。