0. 时间复杂度

接触到算法的小伙伴们都会知道时间复杂度(Time Complexity)的概念,这里先放出(渐进)时间复杂度的定义:

假设问题规模是\(n\),算法中基本操作重复执行的次数是\(n\)的某个函数,用\(T(n)\)表示,若有某个辅助函数\(f(n)\),使得

\[\lim_{n\rightarrow \infty}{T(n)/f(n)} = c
\]

其中\(c\)为不等于零的常数,则称\(f(n)\)是\(T(n)\)的同数量级函数。记作\(T(n)=O(f(n))\),称\(O(f(n))\) 为算法的渐进时间复杂度,简称时间复杂度。

常见的时间复杂度有(表格越靠后表示越不理想):

复杂度 名称
\(O(1)\) 常数阶
\(O(\log n)\) 对数阶
\(O(n)\) 线性阶
\(O(n\log n)\) 线性对数阶
\(O(n^2)\) 平方阶
\(O(n^3)\) 立方阶
\(O(n^k)\) \(k\)次方阶(\(k>3\)且\(k\in Z\))
\(O(2^n)\) 指数阶

例如,我们熟悉的插入排序(Insertion Sort)算法的时间复杂度是\(O(n^2)\),而合并排序(Merge Sort)算法的时间复杂度是\(O(n\log n)\)

那么这些复杂度之间的差距是怎么样的呢?有些小伙伴会疑问,自己写的算法虽然是高复杂度但是也用的好好的,为什么要纠结于这个概念呢?

我们不妨来探索一下今天的问题:\(O(n^2)\)和\(O(n\log n)\)差距有多大?

1. \(O(n^2)\)和\(O(n\log n)\)差距有多大?

我们知道,插入排序(Insertion Sort)算法的时间复杂度是\(O(n^2)\),而合并排序(Merge Sort)算法的时间复杂度是\(O(n\log n)\),即当排序\(n\)个对象时,插入排序算法需要用时大约\(c_1n^2\),而合并排序算法需要用时大约\(c_2n\log{n}\),其中\(c_1\)和\(c_2\)都是正常数且与\(n\)无关,且往往\(c_1<c_2\)。

稍微利用初等数学的知识,可以知道,对于任何\(n>=2\),比较约\(c_1n^2\)和\(c_2n\log{n}\)即比较\(c_1n\)和\(c_2\log{n}\)。由于我们已知

\[c_1<c_2
\]

以及

\[\log{n} < n
\]

想要比较这两个值的大小,直观的看法就是比较两个不等式谁的差别“更多”。可以证明,当无论\(c_1\)和\(c_2\)差别多么显著,总存在充分大的\(N\)使得当\(n>N\)时,\(c_1n>c_2\log{n}\)。

Introduction to Algorithms中,作者举了一个很有趣的例子:

假设针对同一排序问题,用一台很快的电脑A运行插入排序,用一台很慢的电脑B运行合并排序,问题规模\(n=10^7\):

两台电脑的差别如下,为了使A比B优势显著,作者假设电脑A性能比B强1000倍,并且B运行的代码更低效、且编译器更差(导致需要运行更多的指令):

电脑A 电脑B
每秒运行指令数 \(10^{10}\) \(10^7\)
需要运行的指令总数 \(2n^2\) \(50n\log n\)

这样,A完成任务需要:

\[\frac{2\cdot(10^7)^2}{10^{10}} = 20,000\quad seconds
\]

而B完成任务需要:

\[\frac{50\cdot 10^7\log 10^7}{10^{7}} \approx 1,163 \quad seconds
\]

可以看到,在这样的大规模的问题下,即便B计算机与A差距巨大,最终也只用了20分钟左右就完成排序,而A却需要5.5小时来完成。时间复杂度的差距可见一斑。

3. 总结

算法时间复杂度的量级差异,也许在小规模的问题下,表现差别不大。但是时间复杂度高的算法,对问题规模的变化更加敏感,因而当问题的规模变得很大的时候,靠拥有高阶时间复杂度的算法来求解并不可靠!

(更新)我从网络上找到了一个直观的各个阶的复杂度的对比,大家不妨参考一下:

# 喜欢就点个赞、关注支持一下吧!

参考:

Thomas H. Cormen, et al., Introduction to Algorithms Part I 1.2

http://www.bigocheatsheet.com

时间复杂度O(n^2)和O(nlog n)差距有多大?的更多相关文章

  1. 如何快速求解第一类斯特林数--nlog^2n + nlogn

    目录 参考资料 前言 暴力 nlog^2n的做法 nlogn的做法 代码 参考资料 百度百科 斯特林数 学习笔记-by zhouzhendong 前言 首先是因为这道题,才去研究了这个玩意:[2019 ...

  2. 【转】Java学习—什么是时间复杂度

    [原文]https://www.toutiao.com/i6593144782992704007/ 转载:程序员小灰 时间复杂度的意义 究竟什么是时间复杂度呢?让我们来想象一个场景: 某一天,小灰和大 ...

  3. 日常分享:关于时间复杂度和空间复杂度的一些优化心得分享(C#)

    前言 今天分享一下日常工作中遇到的性能问题和解决方案,比较零碎,后续会持续更新(运行环境为.net core 3.1) 本次分享的案例都是由实际生产而来,经过简化后作为举例 Part 1(作为简单数据 ...

  4. careercup-高等难度 18.6

    18.6 设计一个算法,给定10亿个数字,找出最小的100万个数字.假定计算机内存足以容纳全部10亿个数字. 解法: 方法1:排序 按升序排序所有的元素,然后取出前100万个数,时间复杂度为O(nlo ...

  5. [学习笔记] 多项式与快速傅里叶变换(FFT)基础

    引入 可能有不少OIer都知道FFT这个神奇的算法, 通过一系列玄学的变化就可以在 $O(nlog(n))$ 的总时间复杂度内计算出两个向量的卷积, 而代码量却非常小. 博主一年半前曾经因COGS的一 ...

  6. 最小k个数

    题目 输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,. 思考 方法0: 直接排序然后返回前k个,最好的时间复杂度为 O(nlo ...

  7. 排序算法——(2)Python实现十大常用排序算法

    上期为大家讲解了排序算法常见的几个概念: 相关性:排序时是否需要比较元素 稳定性:相同元素排序后是否可能打乱 时间空间复杂度:随着元素增加时间和空间随之变化的函数 如果有遗忘的同学可以看排序算法——( ...

  8. 20172328 2018-2019《Java软件结构与数据结构》第五周学习总结

    20172328 2018-2019<Java软件结构与数据结构>第五周学习总结 概述 Generalization 本周学习了第九章:排序与查找,主要包括线性查找和二分查找算法和几种排序 ...

  9. 超详细的HashMap解析(jdk1.8)

    目录 一.预备知识 时间复杂度 基本数据结构 基本位运算 二.HashMap实现原理 结构 速度 三.源码分析 基本常量 基本成员变量 构造方法 put方法 remove 四.日常使用注意事项 五.总 ...

随机推荐

  1. vue-cli快速原型开发

    我们知道vue-cli提供了一套如何快速搭建vue开发脚手架的工具,虽然好用,但是有的时候我们还是嫌麻烦,因为就想快速开发调试一个组件,这时我们就可以使用vue-cli 3.x以上版本的一个好特性: ...

  2. 洗礼灵魂,修炼python(20)--自定义函数(1)—基础概念

    作为开发,那么我们前面学的那些知识其实够了,但是不够精简,也不好维护,比如需要打印斐波那契数列: 而当我们需要再次打印斐波那契数列,又要把这段代码加上,是不是很烦,有没有方法可以解决,当然可以,那就是 ...

  3. Java动态生成类以及动态添加属性

    有个技术实现需求:动态生成类,其中类中的属性来自参数对象中的全部属性以及来自参数对象properties文件. 那么技术实现支持:使用CGLib代理. 具体的实现步骤: 1.配置Maven文件: &l ...

  4. virtualenv 的使用

    首先,我们用pip安装virtualenv: 一.使用与启动: $ pip3 install virtualenv 然后,假定我们要开发一个新的项目,需要一套独立的Python运行环境,可以这么做: ...

  5. Windows:Oracle 11g 备份脚本

    @echo off echo ================================================ echo Windows环境下Oracle数据库的自动备份脚本 echo ...

  6. python 计时累积超过24小时时继续往上累加

    最近在做一个工具,要求在工具上面加上程序运行的时间,所以做了个计时器 在网上找了很多发现都是24小时制的,超过24小时后就会回0 然后自己根据24小时制修改了一个不停累加时间的 若是想超过24小时后以 ...

  7. Nginx服务器的图片防盗链

    全站的防盗链方法 在/usr/local/webserver/nginx/conf//vhost/xxxx.conf文件要添加防盗链的server段里添加下面的代码: location ~ .*\.( ...

  8. Django之Form进阶

    s6day76 内容回顾: Form组件:  - 类  继承Form  - 字段  字段  - 实例化  - is_valid()  - cleaned_data  - errors Form 组件: ...

  9. mysql-修改字段类型和修改字段名称

    文章转自:https://blog.csdn.net/u010002184/article/details/79354136 mysql修改字段类型: --能修改字段类型.类型长度.默认值.注释 -- ...

  10. Shell命令解析

    1.简单语法: 执行shell:                                sh executeTest.sh puttyy上跑java:                      ...