复杂性
计算复杂性指出了算法的应用需要付出多大的代价。一般涉及两种效率标准,时间和空间。时间因素比空间因素更重要,因此效率的考虑通常都是集中在处理数据耗费的时间上。(编译执行的程序比解释执行的程序运行得快)
通过计算给出源函数效率的近似结果的效率尺度称为渐变复杂度,对于处理大量数据的函数来说,近似结果用于忽略函数的某些项,非常接近真实值。
算法复杂度速查
https://mp.weixin.qq.com/s/brg9JlEB8zoWXhBc-BxUcw?
大O表示法
定义:
如果存在正数c和N使得对所有的n>=N都有f(n)<=cg(n),那么f(n)=O(g(n))。
对f和g的关系可以这样描述:g(n)是f(n)值的上界。
例如: f(n) = 2n²+3n+1 = O(n²)
性质:
- 加法规则
T(n,m) = T1(n) + T2(n) = O (max (f(n),g(m))
- 乘法规则
T(n,m) = T1(n) * T2(m) = O (f(n) * g(m))
特例,如果T1(n) = O(b) ,b是一个与n无关的任意常数,T2(n) = O (f(n)),则有
T(n) = T1(n) * T2(n) = O (b*f(n)) = O(f(n))。
也就是说,在大O表示法中,任何非0正常数都属于同一数量级,记为O(1)。
- 传递性
f(n) = O(g(n)) 且 g(n) = O(h(n)),则 f(n) = O(h(n)) 。
- 有关对数的性质
对任意的正数a和b不等于1,函数 ㏒(a)n = O(㏒(b)n)。
因为对数的底数和大O是不相关的,所以总是可以用同一个基数,故上式可写为:
对于任意正数a不等于1,㏒(a)n 是O(lg n),其中 lg n = ㏒(2)n。
注:还有大Ω表示函数的下界,Θ表示法既是上界也是下界。
计算时间复杂度
常数阶
int Fun(void) {
printf("Hi, 算法!\n"); //需要执行 1 次
return 0; //需要执行 1 次
}
上面算法的运行函数为f(n)=2,2为常数,所以这个算法的时间复杂度为O(1)。
线性阶
void Fun(int n) {
for(int i = 0; i < n; i++) { // 循环次数为 n
printf("Hi, 算法!\n"); // 循环体时间复杂度为 O(1)
}
}
上述循环的时间复杂度为O(n*1),即O(n)。
对数阶
void Fun(int n) {
for (int i = 0; i < n; i++) {
i *= 2;
printf("Hi, 算法!\n", i);
}
}
假设循环次数为 x,则循环条件满足 2^x < n。
可以得出,执行次数x = log₂n,因此这个算法的时间复杂度为 O(lg n)。
化简规则:
1.去掉常数项
2.去掉常数系数
3.只保留最高次项
注意:
- 当有若干个循环语句时,算法的时间复杂度是由嵌套层数最多的循环语句中最内层语句的频度f(n)决定的。
- 顺序语句的运行时间的函数是将各个语句的运行时间求和,之后在根据函数求时间复杂度。
- 选择语句的运行时间总是不会超过最长运行时间的那个函数。
补偿复杂性
暂时还未参透,了解后会补上。
引用
[1]《数据结构与算法》(java语言版) 第二章—复杂度分析
[2]百度百科: https://baike.baidu.com/item/算法复杂度/210801?fr=aladdin
[3]CSDN论坛: https://blog.csdn.net/itachi85/article/details/54882603
[4]博客园:https://www.cnblogs.com/mm93/p/7274670.html