数据结构-----算法复杂度(大O表示法)
为什么要先聊这个算法复杂度呢?
首先,我们先聊聊算法。“老衲”经常听别人说起算法,但还是不太明白算法是什么。
先拽一大段概念:
算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。如果一个算法有缺陷,或不适合于某个问题,执行这个算法将不会解决这个问题。不同的算法可能用不同的时间、空间或效率来完成同样的任务。一个算法的优劣可以用空间复杂度与时间复杂度来衡量。
是不是看不懂,不想看?让我用白话文给你道道:
算法,在日常生活中也是随处可见的。比如“老衲”要去上学,怎么去上学?
- 做飞机,机票贵(引申到程序上就是耗费空间),但是时间快呀
- 坐火车,火车票便宜,但老衲肯定要好久才能到学校,时间又耗费了很多
其实,上面的两种策略就是算法。也就是为了达到“去学校”这一目的,根据自身情况(比如我钱多,我就是要最快到;比如我钱紧张,时间还是很充裕)来选择不同的方式去上学。
同理,算法也有空间复杂度(引申到现实生活就是耗费的价格)和时间复杂度两个标准来衡量它们的好坏。
大O表示法
声明一下,由于个人能力有限,对于时间复杂度和空间复杂度的表示,掌握到了程序的大致表示,如果对复杂度的计算有浓厚的兴趣,可以去看看《c++数据结构与算法》第二章,讲得挺全面!
什么是大O表示法?
come on! 接着来聊,什么是大O表示法呢?
由于程序运行所需的时间往往会受到机器性能与其他因素影响,用绝对的时间单位衡量算法的效率并不合适。在讨论算法复杂度的时候,我们一般关注它的近似值(渐进趋势),即渐进复杂度,常用大O表示法表示。
O(1) | 常数时间复杂度 |
O(log n) | 对数时间复杂度 |
O(n) | 线性时间复杂度 |
O(n^2) | 平方 |
O(n^3) | 立方 |
O(2^n) | 指数 |
O(n!) | 阶乘 |
![](/assets/blank.gif)
可见,几种时间复杂度的增长速度顺序为:O(1) < O(log n) < O(n) < O(n ^ 2) < O(n ^ 3) < O(2 ^ n) < O(n!)
n是什么
n就是算法的输入规模,就是输入数字的数量。
明白了n是什么,就可以大概解释一下7个表达式的含义了。以O(n^2)为例,它表示当输入规模为n时,时间复杂度接近于n^2。
悟出门道了吗?"老衲"说没有。没关系,接下来我将结合代码来解释一下这几种常用时间复杂度的意思。( 如果对程序比较陌生,可以先点开超链接看看我对这块的理解 程序是什么?)
O(1) 常数复杂度
int n = 1000;
System.out.println("Hey - your input is: " + n);
上面这段代码的时间复杂度就是常数级别的,没有循环,一条语句。
int n = 1000;
System.out.println("Hey - your input is: " + n);
System.out.println("Hmm.. I'm doing morestuff with: " + n);
System.out.println("And more: " + n);
这段代码的时间复杂度也是O(1)。
O(log n) 对数复杂度
log n即为log₂n,这里省略了对数的底数2。“老衲”学过高数,对log n一定不会陌生了。
下面这段代码的时间复杂度即为O(log n)。
for(int i = 1; i < n; i = i * 2)
{System.out.println("Hey - I'm busy looking at: " + i);
}
留给“老衲”的思考题:思考一下为什么是 i * 2?
O(n) 线性复杂度
顾名思义,从上面那张图中可以看出函数图像为一条直线。
下面这段代码时间复杂度即为线性阶。单重循环遍历1~n并打印出来,共循环了n次。
for(int i = 1; i <= n; i ++)
{ System.out.println("Hey - I'm busy looking at: " + i);
}
O(n^2) 平方
明白了n次单重循环时间复杂度为O(n),就不难理解下面的双重循环嵌套,共运行n*n次,即时间复杂度为O(n^2)了吧。
for (int i = 1; i <= n; i ++)
{ for (int j = 1; j <= n; j ++){ System.out.println("Hey - I'm busy looking at: " + i + " and " + j); }
}
O(n^3) 立方
以此类推,聪明的“老衲”一定能猜到O(n^3)时间复杂度的程序该怎么写。
O(2^n) 指数
下面代码的时间复杂度就是O(2^n)。
for (int i = 1; i <= Math.pow(2, n); i++){ System.out.println("Hey - I'm busy looking at: " + i);
}
O(n!) 阶乘
public static int fibonacci(int n)
{ // 这个方法的功能是递归求第n个斐波那契数if(n == 1 || n == 2)return 1;elsereturn fibonacci(n - 1) + fibonacci(n - 2);
}public static void main(String[] args)
{for(int i = 0; i < fibonacci(6); i ++) // 这里的for循环对时间复杂度影响不大System.out.println("Hey - I'm busy looking at: " + i);
}
O(n!)复杂度常出现在递归的算法中。上面的代码功能为递归求解第n个斐波那契数,时间复杂度为O(n!)。
递归没有理解没关系,这里简单介绍一下,如果想要深入理解递归请点击超链接查看我的另一篇博客:(此处应有超链接)
先来看看上面代码中用到的公式:
fibonacci(n) = fibonacci(n-1) + fibonacci(n-2) // 这是斐波那契的一种写法
代入一个数,比如6,画出递归树看一下这段代码是如何运行的:
![](/assets/blank.gif)
不难看出来,运行这小小的一句代码时间成本巨大,只是一个小小的6,就让计算机运行了6!次,显然是不划算的。
在后面的算法文章里面,会细致地讲讲如何通过不同的方式来降低算法复杂度!
如何计算算法的渐进复杂度?
当我们得到算法的运行次数后,可以通过以下三步求出大O表示法表示的渐进时间复杂度:
- 用常数1取代运行时间中左右加法常数
- 在修改后的运行次数函数中只保留最高阶项
- 如果最高阶项存在且不是1,则去除与这个项相乘的常数
举几个例子:
执行次数 |
阶 |
非正式术语 |
12 |
O(1) |
常数阶 |
2n + 3 |
O(n) |
线性阶 |
3n^2+2n+1 |
O(n^2) |
平方阶 |
|
O(log n) |
对数阶 |
|
O(n^3) |
立方阶 |
2^n |
O(2^n) |
指数阶 |
递归 | O(n!) | 阶乘阶 |
结束语
明白了7个大O表示法,可以返回去看看折线图,它反映了当n为不同值时,不同渐进时间复杂度的增长趋势!
“老衲”, 你理解了吗?
数据结构-----算法复杂度(大O表示法)相关推荐
- 算法与数据结构(part1)--算法简介及大O表示法
学习笔记,仅供参考 文章目录 算法与数据结构--基于python 数据结构和算法简介 算法引入 例题A 算法的概念 例题A的优化 算法效率的衡量 时间复杂度与大O记法 例题A的时间复杂度 如何理解大O ...
- 算法概念:大O表示法/小o表示法/Ω/Θ
如果算法A需要的时间与f(n)成正比,则算法A称为f(n)阶,表示为O(f(n)).函数f(n)称为算法的增率函数(growth-rate function).该表示法使用大写字母O来表示(order ...
- 算法复杂度/大O方法/渐近分析法
A Gentle Introduction to Algorithm Complexity Analysis Dionysis "dionyziz" Zindros dionyzi ...
- 数据结构-算法: 分配排序(基数分配排序法)
基数排序(Radix Sort)是对箱排序的改进和推广. 1.单关键字和多关键字 文件中任一记录R[i]的关键字均由d个分量 构成. 若这d个分量中每 ...
- 数据结构学习笔记:算法复杂度的度量之“大O记号”
分析算法复杂度的非常重要的方法:大O记号!! 下面来让我们看一下到底什么是大O记号 举个例子: 用一个直尺去评价算法复杂度,上面的刻度就相当于大O记号,我们不一定要一味的强调刻度的精细程度,没有必要. ...
- 大O表示法(复杂度分析)
程序 = 数据结构 + 算法 大O表示法 什么是程序?相信学过编程的人都知道,程序由数据结构和算法构成,想要写出好的的程序,首先得了解数据结构和算法.一切脱离数据结构和算法的程序设计都是耍流氓! 什么 ...
- 复杂度分析(大O表示法)
复杂度分析 前文提要 本文完完全全引用极客时间的文章<数据结构与算法之美>,作者王争. 数据结构是作为程序猿绕不过的一道坎,所以萌生了学习的想法,试读了几篇文章后发现讲的很好,也有很多人订 ...
- 数据结构与算法——复杂度
算法是用于解决特定问题的一系列的执行步骤.使用不同算法,解决同一个问题,效率可能相差非常大.为了对算法的好坏进行评价,我们引入 "算法复杂度" 的概念. 1.引例:斐波那契数列(F ...
- 大o表示法描述复杂度_时间复杂度,空间复杂度和大O表示法
大o表示法描述复杂度 This is the first post in my series Data Structures & Algorithms. As a boot camp grad ...
最新文章
- 基于Spring可扩展Schema提供自定义配置支持
- 【百度地图API】建立全国银行位置查询系统(四)——如何利用百度地图的数据生成自己的标注...
- Light-Head R-CNN
- php补充 扩展,php补充安装扩展支持
- 用python阐释工作量证明(proof of work)
- Java高新技术笔记:反射、多线程、泛型、枚举、javaBean、代理
- 【数学题】男女的比例
- Markdown常用转义字符
- js本页导出Excel,下载
- 多叉树/图结构维护问题转线性结构——dfs序
- 俗话说“肩挑四两为客,帮人一日为奴”,这是什么意思?
- mysql 设置密码
- linux下高可用性群集和负载均衡群集的实现
- 未知错误 ID:-2147467259 操作必须使用一个可更新的查询
- 最全面的测试用例--web测试
- 湖南省计算机二级官网2020,湖南2020年3月计算机二级考试报名时间安排
- windows部署tensorflow serving
- 有趣的HTML实例(七) 注册登录界面Ⅱ(css+js)
- Codeforces1696 C. Fishingprince Plays With Array
- Hadoop2.x与Hadoop3.x的默认端口变化