talking:算法的复杂度可以从两个方面来衡量,时间以及空间复杂度,而我们单说复杂度的话一般指时间复杂度。
做个铺垫:
在平常的代码编写中,度量算法的效率一般为事前分析估算,忽略程序中都会有的步骤,着重于每次代码运行都会重复运行的关键步骤并计算出关于其的函数,有了这些函数便可以比较算法的大致效率。
一、时间复杂度
1.定义:T(n) = O(f(n))
随着问题规模n的增大,算法执行时间的增长率和关于n的某一函数f(n)的增长率相同,就称其为算法的渐进时间复杂度,简称为时间复杂度。
(T(n)是语句的总的执行次数,f(n)为关于n的函数)==>
f(n)是关于n的执行次数的函数
-
随着n的增大,增长率越低,即时间复杂度f(n)越小,效率越高。T(n)增长的最慢的算法为最优算法。
-
O(f(n))的记法又被称作大O记法。
2.分类
常见时间复杂度:
- 常数阶:跟问题大小n无关,执行时间恒定,具有O(1)的复杂度。
例如:无循环的简单结构:分支结构等 - 线性阶:O(n)
- 平方阶:O(n2)/O(m*n)
- 对数阶:O(logn)
- 指数阶:O(2n)
- nlogn阶 :O(nlogn)
- 立方阶 :O(n3)
他们的耗费时间的顺序是:
O(1)<O(log n)<O(n)<O(nlog n)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)
但类似n3,n!这种复杂度太高,不切实际的算法一般不讨论。
3.时间复杂度计算方法(大O的算法)
- 常数1取代运行时间中的所有加法常数
- 在修改后的运行次数中只保留最高次数项
- 如果最高阶存在且不是1,则去除与这个项相乘的常数
即某个算法,随着n的增大,函数中的常数及其他次要项常常可以忽略,而更应该该区关注其最高阶项(最高次数项)
4.函数的渐近增长
那计算出来算法的时间复杂度之后呢?
怎么比较多个算法的时间复杂度寻求最优算法?
这里我们引入函数的渐近增长这一概念:
- 定义:对于范围内存在N,使得n>N时,若f(n)总是比g(n)大,则我们说f(n)的渐近增长快于g(n);
- 可以对比算法的时间复杂度函数分析出:某个算法随着n的增大越来越优于/差于另一算法;
5.最坏情况与平均情况
- 因为后期程序测试的未知性,所以一般我们想要得到的是一种平均情况的时间复杂度;
- 从概率的角度看,平均时间复杂度一般是最坏情况的两倍(因为范围中每一种情况出现的概率都一样,平均时间复杂度即中间数的时间复杂度)
- 一般所指的时间复杂度为最坏时间复杂度;
二、空间复杂度
例如:我们在计算闰年的时候,如果已知要计算的年份在某一范围内,你可以写一个算法出来,每次输入一个值的时候判断是不是闰年再输出,当然有一个更省力的方法,提前就把范围内所有年份是否是闰年计算出来再以1/0的形式存入一个数组中,在每次输入的时候就不用每次都动用算法。
这其实就是一个动用一笔空间上的开销来换取计算时间的小技巧。
下面引出空间复杂度:
定义:S(n) = O(f(n))
n为问题规模
f(n)为关于n的所占的储存空间的函数
其余性质与时间复杂度相同。
参考书籍:程杰《大话数据结构》