评定一个算法的优劣指标:
1、正确性,可读性,容错性。
2、复杂度。
本文主要介绍复杂度内容。
研究学习算法的目的就是让程序:运行速度快,节省内存等资源消耗。
复杂度
- (快)时间复杂度: 估算程序执行指令的次数。(执行时间)
- (省)空间复杂度:估算程序运行需要的存储空间。
时间复杂度
分析方法有两种
- 事后统计法 用测试程序和数据来运行已编写好的算法,对其执行时间进行比较。
- 事前统计法 不依赖具体的测试程序和数据,根据统计方法对算法执行效率进行分析的方法。
事后统计法存在各种缺陷,暂不介绍。想了解,找度娘。
事前统计法的计算逻辑是怎么计算的呢?
首先:假设每个代码语句每执行一次的耗时是一样的,记为T
例如:
public void sum(int n) {
int sum = 0; // 执行1次
for(int i = 0; i < n; i++) { // i=0;执行1次; i < n 循环执行n次 ; i++ 循环执行n次
int base = i; // 循环执行n次
}
}
上面这段代码的时间复杂度为:(1+(1+2n)+n)*T = (2+3n)*T 列举时间复杂度的计算:
// 时间复杂度为 1
public void sum(int n) {
if (n % 2 == 0){
System.out.println("偶数");
}else {
System.out.println("奇数");
}
}
// 时间复杂度为 log2(n)
public void sum(int n) {
if ((n = n / 2) > 0){
System.out.println("end");
}
}
计算斐波那契数列的两种方式 ”递归和滚动变量“复杂度对比
// 斐波那契数列:1 1 2 3 5 8 ....n 计算公式: f(n) = f(n-1)+f(n-2)
//*** 递归 时间复杂度估算为 2^n =>O(2^n)
public static long fbiA(int n) {
if(n>0 && n <= 2) return 1;
return fbiA(n-1) + fbiA(n-2);
}
// *** 滚动变量 2 + 1+(n-2)*5 = 5n -7=>O(n)
public static long fbiB(int n) {
if(n>0 && n <= 2) return 1;
long a = 1;
long b = 1;
for(int i = 2;i< n;i++) {
long sum = a+b;
a = b;
b = sum;
}
return b;
}
因为每行代码的执行时间T可以忽略不记。
所以时间复杂度与每行代码的执行次数n成正比。
由于时间复杂度为估算值,但是像这种的(log2(n)、n!、1、5n-7)描述方式太过于繁琐。
所以将所有代码的执行总时间T(n)和每行代码的执行次数n之间的关系表示:
T(n)=O(f(n))
公式中的O表示代码的执行总时间T(n)和其执行总次数f(n)成正比。这种表示法,称之为大O记法
大O记法的原则
- 忽略常数、系数、低阶
| 原表示 | 大O表示法 | 说明 |
|---|---|---|
| 9 | O(1) | 无论9 还是10000都为O(1) |
| 2n+1 | O(n) | |
| n+1 | O(n) | |
| n^2+2n+1 | O(n^2) | |
| n^2+n^2+2n+1 | O(n^3) | |
| log2(n) | log(n) |
空间复杂度
算法的空间复杂度通过计算算法所需的存储空间实现,算法空间复杂度的计算公式记作:S(n)=O(f(n)),其中n为问题的规模,f(n)为语句关于n所占存储空间的函数。
在平时的开发中更多的是用空间换时间,关于算法的空间复杂度就介绍到这里。