大O复杂度表示法
int cal(int n) {
int sum = 0;
int i = 1;
for (; i <= n; ++i) {
sum = sum + i;
}
return sum;
}
假设每行代码执行的时间都为 unit_time:
- 第 2、3 行:分别需要 1 个 unit_time
- 第 4、5 行:循环 n 遍,需要 2n*unit_time
所以这段代码总执行时间为: T(n) = (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;
}
}
}
双层循环:
- 第 2、3、4 行:都需要 1 个 unit_time
- 第 5、6 行:
在这里插入代码片
循环 n 遍,需要 2n * unit_time - 第 7、8 行:循环执行了 n 2 n^2 n2遍,所以需要 2 n 2 2n^2 2n2 * unit_time
所以总执行时间 T(n) = ( 2 n 2 2n^2 2n2+2n+3)*unit_time。
总结出规律:大O时间复杂度表示法
所有代码的执行时间 T(n) 与每行代码的执行次数成正比:
T
(
n
)
=
O
(
f
(
n
)
)
T(n) = O(f(n))
T(n)=O(f(n))
- T(n) 表示代码执行的时间;
- n 表示数据规模的大小;
- f(n) 表示每行代码执行的次数总和;
- 公式中的 O,表示代码的执行时间 T(n) 与 f(n) 表达式成正比。
大O时间复杂度并不具体表示代码执行时间,而是表示代码执行时间随数据规模增长的变化趋势,所以也叫作渐进时间复杂度,简称时间复杂度。
我们只需记录一个最大量级,用大 O 表示法表示以上两段代码的时间复杂度:
T
(
n
)
=
O
(
n
)
;
T
(
n
)
=
O
(
n
2
)
T(n) = O(n); T(n) = O(n^2)
T(n)=O(n);T(n)=O(n2)
时间复杂度分析
三个要点:
- 只关注循环执行次数最多的一段代码:比如第一段代码的4,5行
- 加法法则:总复杂度等于量级最大的那段代码的复杂度
- 乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积
几种常见时间复杂度
- 常量阶: O ( 1 ) O(1) O(1)
- 对数阶: O ( l o g n ) O(logn) O(logn)
以下代码:
i=1;
while (i <= n) {
i = i * 2;
}
2 x = n 2^x = n 2x=n, 解出 x x x 就知道执行次数最多的代码(第3行)的执行次数, x = l o g 2 n x = log_{2} ^n x=log2n,所以时间复杂度为: O ( l o g 2 n ) O( log_{2} ^n) O(log2n),可以即为 O ( l o g n ) O( logn) O(logn),因为 O ( l o g 2 n ) O( log_{2} ^n) O(log2n) 和 O ( l o g 3 n ) O( log_{3} ^n) O(log3n) 之间仅仅相差一个常量 C = l o g 3 2 ) C = log_{3} ^2) C=log32)。
- 线性阶: O ( n ) O(n) O(n)
- 线性对数阶: O ( n l o g n ) O(nlogn) O(nlogn)
O ( l o g n ) O(logn) O(logn)的代码循环 n n n次。。。
- 平方阶: O ( n 2 ) O(n^2) O(n2)
- 立方阶: O ( n 3 ) O(n^3) O(n3)
- 指数阶: O ( 2 n ) O(2^n) O(2n)
- 阶乘阶: O ( n ! ) O(n!) O(n!)
以上复杂度可以简单分两类:多项式量级和非多项式量级。非多项式量级只有两个: O ( 2 n ) O(2^n) O(2n), O ( n ! ) O(n!) O(n!)。
非多项式量级的算法问题叫作 NP(Non-Deterministic Polynomial,非确定多项式)问题。
空间复杂度分析
空间复杂度就是渐进空间复杂度(asymptotic space complexity),表示算法的存储空间与数据规模之间的增长关系。