如何看懂时间复杂度的big-O表达式

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表达式以及对应代码示例

  1. O(1)

表示时间复杂度是一个常数,总耗时恒定。

int getMax(int a,int b) noexcept
{
    return a > b ? a : b;
}
  1. 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;
}
  1. 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表示法_百度百科 (baidu.com)

O(log(N))是什么意思 - 知乎 (zhihu.com)

常见的大O表示法有哪些?时间复杂度是什么?(bilibili.com)

本文使用的函数图像生成并截取自Desmos | 图形计算器

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值