0. 时间复杂度
接触到算法的小伙伴们都会知道时间复杂度(Time Complexity)的概念,这里先放出(渐进)时间复杂度的定义:
假设问题规模是,算法中基本操作重复执行的次数是
的某个函数,用
表示,若有某个辅助函数
,使得
![\lim_{n\rightarrow \infty}{T(n)/f(n)} = c](https://i-blog.csdnimg.cn/blog_migrate/f1588bb7c8e4b2edd4e37aa1b50e6e44.png)
其中为不等于零的常数,则称
是
的同数量级函数。记作
,称
为算法的渐进时间复杂度,简称时间复杂度。
常见的时间复杂度有(表格越靠后表示越不理想):
复杂度 | 名称 |
---|---|
![]() | 常数阶 |
![]() | 对数阶 |
![]() | 线性阶 |
![]() | 线性对数阶 |
![]() | 平方阶 |
![]() | 立方阶 |
![]() | ![]() ![]() ![]() |
![]() | 指数阶 |
例如,我们熟悉的插入排序(Insertion Sort)算法的时间复杂度是,而合并排序(Merge Sort)算法的时间复杂度是
那么这些复杂度之间的差距是怎么样的呢?有些小伙伴会疑问,自己写的算法虽然是高复杂度但是也用的好好的,为什么要纠结于这个概念呢?
我们不妨来探索一下今天的问题:和
差距有多大?
1.
和
差距有多大?
我们知道,插入排序(Insertion Sort)算法的时间复杂度是,而合并排序(Merge Sort)算法的时间复杂度是
,即当排序
个对象时,插入排序算法需要用时大约
,而合并排序算法需要用时大约
,其中
和
都是正常数且与
无关,且往往
。
稍微利用初等数学的知识,可以知道,对于任何,比较约
和
即比较
和
。由于我们已知
以及
![\log_2{n} < n](https://i-blog.csdnimg.cn/blog_migrate/d6e8990184b54daf08f4627328bb646f.png)
想要比较这两个值的大小,直观的看法就是比较两个不等式谁的差别“更多”。可以证明,当无论和
差别多么显著,总存在充分大的
使得当
时,
。
在Introduction to Algorithms中,作者举了一个很有趣的例子: 假设针对同一排序问题,用一台很快的电脑A运行插入排序,用一台很慢的电脑B运行合并排序,问题规模:
两台电脑的差别如下,为了使A比B优势显著,作者假设电脑A性能比B强1000倍,并且B运行的代码更低效、且编译器更差(导致需要运行更多的指令):
电脑A | 电脑B | |
---|---|---|
每秒运行指令数 | ![]() | ![]() |
需要运行的指令总数 | ![]() | ![]() |
这样,A完成任务需要:
![\frac{2\cdot(10^7)^2}{10^{10}} = 20,000\quad seconds](https://i-blog.csdnimg.cn/blog_migrate/2cd80f2e390ce94f4226de17bd6bbdc8.png)
而B完成任务需要:
![\frac{50\cdot 10^7\log_2 10^7}{10^{7}} \approx 1,163 \quad seconds](https://i-blog.csdnimg.cn/blog_migrate/1aaff0bba4257302a47ce2fe67459a19.png)
可以看到,在这样的大规模的问题下,即便B计算机与A差距巨大,最终也只用了20分钟左右就完成排序,而A却需要5.5小时来完成。时间复杂度的差距可见一斑。
3. 总结
算法时间复杂度的量级差异,也许在小规模的问题下,表现差别不大。但是时间复杂度高的算法,对问题规模的变化更加敏感,因而当问题的规模变得很大的时候,靠拥有高阶时间复杂度的算法来求解并不可靠!
# 喜欢就点个赞支持一下吧!
复制代码
参考:
Thomas H. Cormen, et al., Introduction to Algorithms Part I 1.2