0x0:一些例子
从前我一直看不懂这些,其实大抵还是因为懒,最近终于有一些理由让我去查一些资料了,所以顺手写一点。我也不是什么大佬,理解上难免有偏差,如果有误,烦请各位指出,感谢。
不知道你在学习算法的过程中,有没有遇见过这几个东西:
-
O(1)
-
O(n)
-
O( x 2 x^2 x2)
-
O(n log n)
-
O(n)
-
O(log n)
-
O(n!)
-
O( 2 n 2^n 2n)
这是时间复杂度的大O表示法,其中的O是一个函数,定义为T[n] = O(f(n)),它不仅可以表示时间的复杂度,还能表示空间的复杂度。
那么,什么是时间复杂度呢?
0x1:时间复杂度
试想一下,如果我给你这样一排…P,请你挨个拾取它们。
听起来就很容易,那这样呢?
(我知道图糊了,但是懒得换)
很明显,如果设P点的个数为x,捡起一个P点需要的时间固定,那么对于捡起所有P点所耗费的时间总量t在大体上有如下图像:
这实际上是一个 y = x (x ⩾ \geqslant ⩾ 0,下略) 图像
类似的,如果我要求你每捡起一个P点就释放P点总数个Bomb,那图像会变成这样:
这实际上是一个 y = x 2 x^2 x2 图像
拿第一个例子来说,像这样的,以捡起所有P点为例,这个操作所需要耗费的时间 t 随着P点数量 x 的增多,以一个恒定的速率 k(假设捡起两个P点的操作之间没有间隔,k为捡起一个P点的用时),那么就有 t = kx,由此我们可以说:这个操作的时间复杂度可以表示为 O(n)
现在你再看看那些 O(1),O( n 2 n^2 n2),是不是有点感觉了?
0x2:big-O表达式
O(…),即大O表达式(big-O),常用于表达某种操作(算法)的耗时上界,它从大体上粗略地描述了一个算法所需要的时间,即它的时间复杂度。正如前例,big-O表达式使用一个简单的式子来从大体上形容一种耗时的概念,通过big-O表达式,我们能一眼看出操作大体上的时间复杂度,即耗时与数据量的大体关系。
需要注意的是,就以O( n 2 n^2 n2)而言,经管实际上的耗时可能并不是t = n 2 n^2 n2(或者是我们举的第一个例子,捡起两个P点之间是肯定有时间间隔的),只是因为某种关系,它的整体耗时的变化曲线和 y = x 2 x^2 x2 类似(至少看起来有那么一点类似),所以我们可以用 O( n 2 n^2 n2) 来形容它的时间复杂度。
数学需要讲究逻辑的严密,准确,但我们学的毕竟不是真正的数学。
0x3:三个简单的大O表达式以及对应代码示例
- O(1)
表示时间复杂度是一个常数,总耗时恒定。
int getMax(int a,int b) noexcept
{
return a > b ? a : b;
}
- O(n)
表示时间复杂度解析图像类似于 y = x 的图像,总耗时随着处理量的增加而线性增长。
int getMax(std::initializer_list<int> list) noexcept
{
int buffer = INT_MIN;
for(auto& item : list) if(item > buffer) buffer = item;
return buffer;
}
- O( n 2 n^2 n2)
表示时间复杂度解析图像类似于 y = x 2 x^2 x2 图像,随着处理量的增加,总耗时成次方增长。
void foreachAudioListDo(AudioListManager& manager) noexcept
{
for(auto& list : manager)
{
for(auto& sound : list) sound.play();
}
}
0x4:big-O的加法
之前提过一点,时间复杂度表示的是上界(极限),当两个算法共用(此处不考虑嵌套)时,整体的时间复杂度未必是直接相加,全看二者之中占大头者,例如:
O(n) + O( 2 n 2^n 2n) = O( 2 n 2^n 2n)
0x5:关于O(log n)
需要注意的是,这里的 log 是省略了下标 2 的,实际上应该写做 O( l o g 2 log_2 log2n) ,但是这样做毕竟太麻烦,在一些环境下也打不出这个下标,就简化到只留下 log 了。
带 log 的几个大O表达式都比较迷惑人,实际上,同其他任何的大O表达式一样,只要画出他们的图像即可。
这是 y = l o g 2 log_2 log2x 的图像
O(log n) 的一个典型例子是二分查找,在二分查找中,每查找一次,下一次查找所需要处理的数据量就是上一次的一半。
别看着 l o g 2 log_2 log2n 好像很复杂,实际上,O( l o g 2 log_2 log2n) 介于 O(n) 和 O(1) 之间,是全体程序员努力的方向。
0x6:参考资料
O(log(N))是什么意思 - 知乎 (zhihu.com)
常见的大O表示法有哪些?时间复杂度是什么?(bilibili.com)
本文使用的函数图像生成并截取自Desmos | 图形计算器