一、什么是算法复杂度?
算法进行计算的时候,存储数据需要占用一定的 空间,执行计算需要耗费一定的时间 时间。算法复杂度就是在算法计算过程中对「空间」与「时间」的评价。
解决同一个问题,不同算法所有的空间和时间是不同的,这取决于算法是如何设计的。同样,同一个问题,规模不同时,同一个算法所用的空间和时间也不同。
例如:某排序算法为 100 个数排序和为 1000 个数排序。
所以,一个算法的复杂度是问题规模 N 的函数。
二、时间复杂度
时间复杂度是算法执行计算所花费的时间多少的度量,但是不同的机器计算速度不同,实际的时间很难统计,由此可以通过统计算法执行的语句数来表示时间复杂度。
1. 渐进时间复杂度
随着问题规模 n 的增大,常数部分的影响越来越小:T(n) = 2$n^3$ + 4n + $logn$ + 4;而增长最快的项影响越来越大($n^3$):T(n) = 2$n^3$ + 4n + $logn$ + 4。
渐进时间复杂度只关注增长最快的项:T(n) = O($n^3$),去除常数系数与复杂度小的项。平时说代码的时间复杂度,一般指渐进时间复杂度。
$n^n$ > $n!$ > $c^n$ > $n^c$ > $log_cn$ > c,$logn$ 一般表示 $log_2n$。
2. 代码结构与渐进复杂度
分析代码复杂度时,可以按结构分析,再组合:
- 嵌套结构相乘:$O(x) * O(y) = O(xy)$
- 顺序结构相加:$O(x) * O(y) = max(O(x),O(y))$
3. 常见代码结构的时间复杂度
1. 常数次数
时间复杂度:$O(1)$
int a = 10;
int b = a;
int N = 8;
2. 嵌套结构
循环次数 * 一次迭代次数,时间复杂度:$O(N)$
for(int i = 0; i < N; i++){
int a = 16 / 4;
int b = a * 3;
}
3. 多重嵌套结构
各个循环次数相乘,时间复杂度:O($N^2$)
for(int i = 0; i < N; i++)
for(int j = 0; j < N; j++){
int a = 16 / 4;
int b = a * 3;
}
4. 顺序结构
各部分相加,时间复杂度:O($N$)
for(int i = 0; i < N; i++){
int a = 16 / 4;
int b = a * 3;
}
for(int i = 0; i < N; i++){
int a = 16 / 4;
int b = a * 3;
}
5. 循环次数
除法次数:$N/2$,时间复杂度:$O(N)$
for(int i = 0; i < N; i = i + 2){}
对数次数:$log_2N$,时间复杂度:$O(logN)$
for(int i = N; i >= 0; i = i / 2){}
6. 递归
三、空间复杂度
空间复杂度同样可以用 $O()$ 来衡量,与时间复杂度分析类似,既要考虑算法处理的数据,也要考虑辅助变量。
算法分析的过程中更多关注时间复杂度。