复杂度分析
复杂度也叫渐进复杂度,包括时间复杂度和空间复杂度,用来分析算法执行效率与数据规模之间的增长关系。
基本概念
前提:每行代码都执行类似的操作:读数据 - 运算 - 写数据,所以粗略估计每行代码执行时间一样,为 unit_time
int cal(int n) {
int sum = 0;
int i = 1;
for (; i <= n; ++i) {
sum = sum + i;
}
return sum;
}
(2n+2) * unit_time
int cal(int n) {
int sum = 0;
int i = 1;
int j = 1;
for (; i <= n; ++i) {
j = 1;
for (; j <= n; ++j) {
sum = sum + i * j;
}
}
}
(3 + 2n + 2n²) * unit_time
所有代码的执行时间 T(n) 与每行代码的执行次数 n 成正比
T(n) = O(f(n))
T(n)
表示 代码执行的时间
n
表示 数据规模的大小
f(n)
表示 每行代码执行次数的总合
所以 公式中 O
表示 T(n)
与 f(n)
成正比
上面的可以表示为 T(n) = O(2n + 2)
T(n) = O(3 + 2n + 2n²)
这就是大 O 时间复杂度表示法。并不是表示代码执行时间,而是代码执行时间随数据规模增长的变化趋势
公式中的 低阶、常量、系数并不左右增长趋势,所以可以忽略。所以可以记为 T(n) = O(n)
T(n) = O(n²)
时间复杂度分析
只关注循环执行次数最多的一段代码
加法法则:总复杂度等于量级最大的那段代码的复杂度
即:
T(n) = O(10000 + n + n²)
取最大量级,常量级忽略,结果为T(n) = O(n²)
乘法法则:嵌套代码的复杂度等于嵌套内外复杂度的乘积
T(n) = T1(n) * T2(n) = O(n*n) = O(n²)
常见的时间复杂度分析
指数阶、阶乘阶可以分类为非多项式量级,n 越大,执行时间急剧增加,非常低效。
O(1)
一般情况下,只要算法中不存在循环语句、递归语句,即使有成千上万行的代码,其时间复杂度也是Ο(1)
O(㏒n)、O(n㏒n)
对数阶比较难分析
i=1;
while (i <= n) {
i = i * 2;
}
以 2 为底 n 的对数,不论是以 2 为底,还是以 10 为底,都算作 O(㏒n)
O(m+n)、O(m*n)
代码复杂度由两个数据规模决定
空间复杂度
void print(int n) {
int i = 0;
int[] a = new int[n];
for (i; i <n; ++i) {
a[i] = i * i;
}
for (i = n-1; i >= 0; --i) {
print out a[i]
}
}
第 2 行 申请了 1 个空间存储变量
第 3 行 申情了 n 个空间存储变量
剩下的没有占用更多空间,所以空间复杂度为 O(n)
复杂度分析
最好情况时间复杂
在最理想的情况下,执行这段代码的时间复杂度
最坏情况时间复杂度
在最糟糕的情况下,执行这段代码的时间复杂度
平均情况时间复杂度
这个值就是概率论中的加权平均值,也叫作期望值,所以平均时间复杂度的全称应该叫加权平均时间复杂度或者期望时间复杂度