时间复杂度全称为渐进时间复杂度,表示算法的执行时间与数据规模之间的增长关系.
大O表示法
- 先看一段代码
1
2
3
4
5
6
7
8func cal (n int ) int {
i := 0
sum := 0
for ;i < n ; i++ {
sum += i
}
return sum
} - 从CPU角度来看,这些代码都是读数据 运算 写数据 ,这里把每一行代码运行时间都记为unit_time;
- 第一行和第二行运行时间分别都是1个unit_time
- 第四行和第五行运行时间都为n个unit_time 这里记为2n个unit_time
- 所以这段代码的运行时间为2n+2个unit_time
- 可以看出来所有的代码的执行时间T(n)与每行代码执行的次数成正比
- 在看以下一段代码
1 | func cal (n int ) int { |
- 这里每行代码运行时间单位还是unit_time
- 第2,3,4行都是1一个unit_time,即3个unit_time
- 5,6行分别都是n个unit_time,即2n个unit_time
- 7,8行分别都是n个unit_time,即n²个unit_time
- 最后得出结果是2n+2n²+3个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(2n²+2n+3),这个就是大O时间复杂度表示法,大O表示法并不能很精确的计算出代码真正的执行时间,只是能表示出来代码执行时间随着数据规模的增长而增长,所以也称为渐进时间复杂度,简称时间复杂度;
- 公式中的低阶 常量 系数都不会左右T(n)的大小,所以这里只需要记录一个最大的数据量,以上的例子公式就可以简写为 1.T(n) = O(n) 2. T(n) = O(n²);
时间复杂度分析
- 只关注循环执行次数最多的一段代码,表示为O(n);
- 加法法则:总复杂度等于量级最大的那段代码的复杂度 如果是O(n²)+O(n³)那么结果就是T(n) = O(max(O(n²),O(n³));
- 乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积,如果是 T1(n) = O(n) T2(n) = O(n) 那么结果就是 T(n)=O(n²)
常见的时间复杂度
- O(1)
- 一般情况下,只要算法中不存在递归,循环,这段代码的时间复杂度就是O(1);
- O(logn) O(nlogn)
1
2
3
4
5
6
7for ;; {
i++
i *= 2
if i > Count {
break
}
}
- 如果是对数复杂度,那么忽略底数,统一记为O(logn)
- 如果一段代码的复杂度是O(logn),循环N遍,那么他的复杂度就是O(nlogn)
- O(m+n) O(m*n)
1
2
3
4
5
6
7
8
9
10
11
12func cal(m int,n int ) int {
sum := 0
i := 0
for ; i < m ; i++ {
sum += i
}
j := 0
for ; j < n; j++ {
sum += j
}
return sum
}
- 看代码得出这段代码的数据规模是有m和n来决定的,如果没有实际数据是无法评估出来复杂度的,所以这里的复杂度就是O(m+n)
空间复杂度分析
空间复杂度全称为渐进空间复杂度,表示算法的存储空间与数据规模之间的增长关系.
- 常见的空间复杂度有O(1) O(n) O(n²) O(logn) O(nlogn)
总结
- 复杂度也叫渐进复杂度,包括时间复杂度和空间复杂度,用来分析算法的执行效率与数据规模之前的增长关系,越高阶复杂度的算法,执行效率越低.
- 低阶到高阶的的复杂度有:O(1) O(logn) O(n) O(nlogn) O(n²)