评价算法优劣的维度
-
正确性、可读性、健壮性(对不合理输入的反应能力,也称为鲁棒性):这三个指标是基本的首要的维度。
-
时间复杂度:是一个函数,用于定性描述算法的运行时间。常用大O表示法,该方法不包含函数的低阶项和首项系数,是一种渐近表达。
- 一般来说,计算机执行一条指令消耗的时间大致相同,那么包含多条指令的程序段的总执行时间同指令的执行次数正相关,可认为时间复杂度O是指令执行次数n的函数,即O(n)=f(n)。
- 在分析算法时,估算执行次数最多的指令的最高阶表达式作为算法的时间复杂度,且最高阶表达式不带系数。
- 如上所述,分析时间复杂度是获取执行次数,即根据程序的特点,计算出最里层的指令需要执行的次数。
-
空间复杂度:程序执行所消耗的存储空间。在分析算法时,估算指令的存储空间作为算法的空间复杂度。
时间复杂度分析
对数阶时间复杂度分析
//情况1 n每次以1/5的速度缩小,直至小于0
//时间复杂度取决于 n 缩小的次数
public static void test1(int n){
while((n = n/5) > 0){
System.out.println("test1")
}
}
//情况2 i每次扩大2倍,直至i大于n
//时间复杂度取决于 i 扩大的次数
public static void tes2(int n){
for(int i = 1; i < n; i = i * 2){
System.out.println("test2")
}
}
在情况1代码中,执行最多的指令是最里层代码是打印test语句,那么这段程序的时间复杂度是和打印语句的执行次数正相关,而执行次数取决于while的判断条件。由于每循环一次 n缩小为原来的1/5,那么总的次数total满足公式 5total = n,可得total = log5n.类似地,情况2中,i的总扩大次数 total满足公 式 2total = n,可得 total = log2n。
情况1和情况2虽然一个是缩小,一个是扩大,但本质上一致,都是在指定范围内,循环条件成倍数的变化,这种情况一般可通过取对数获取循环次数。
特别地,由于 log5n = log2n / log25,变形得 lgn = log25 * log5n。 其中log25是一个常数,在时间复杂度分析中可以忽略常数,因此lgn等价于log9n。此处以5举例,这个结论同样适用于其他对数阶,即对于任意对数阶的时间复杂度,都可用等价的lgn表示。
常见的时间复杂度
Ο(1)<Ο(lgn)<Ο(n)<Ο(nlgn)<Ο(n2)<Ο(n3)<…<Ο(2n)<Ο(n!)
时间复杂度的图形表示下图,当一个算法的时间复杂度大于n2时,该算法的可用性很差,建议优化算法。
- 使用尽量少的空间
- 使用尽量少的时间
- 空间时间互换
多个数据规模
当程序中存在多个变量时,时间复杂度O应该包含多个变量。
public static void tes3(int n,int m){
for(int i = 1; i < n; i = i * 2){
System.out.println("test3")
}
for(int i = 1; i < m; i = i * 2){
System.out.println("test3")
}
}
在上述代码中,程序的最里层的执行次数受 n m两个变量决定,则其时间复杂度应该表示为O(N + K)。