为什么要先聊这个算法复杂度呢?

首先,我们先聊聊算法。“老衲”经常听别人说起算法,但还是不太明白算法是什么。

先拽一大段概念:

算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。如果一个算法有缺陷,或不适合于某个问题,执行这个算法将不会解决这个问题。不同的算法可能用不同的时间、空间或效率来完成同样的任务。一个算法的优劣可以用空间复杂度与时间复杂度来衡量。

是不是看不懂,不想看?让我用白话文给你道道:

算法,在日常生活中也是随处可见的。比如“老衲”要去上学,怎么去上学?

  1. 做飞机,机票贵(引申到程序上就是耗费空间),但是时间快呀
  2. 坐火车,火车票便宜,但老衲肯定要好久才能到学校,时间又耗费了很多

其实,上面的两种策略就是算法。也就是为了达到“去学校”这一目的,根据自身情况(比如我钱多,我就是要最快到;比如我钱紧张,时间还是很充裕)来选择不同的方式去上学。

同理,算法也有空间复杂度(引申到现实生活就是耗费的价格)和时间复杂度两个标准来衡量它们的好坏。

大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!) 阶乘
以上7种即为常见的时间复杂度/空间复杂度。
这些又有什么含义呢?先来看下面这张图:

可见,几种时间复杂度的增长速度顺序为: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,画出递归树看一下这段代码是如何运行的:

不难看出来,运行这小小的一句代码时间成本巨大,只是一个小小的6,就让计算机运行了6!次,显然是不划算的。

在后面的算法文章里面,会细致地讲讲如何通过不同的方式来降低算法复杂度!

如何计算算法的渐进复杂度?

当我们得到算法的运行次数后,可以通过以下三步求出大O表示法表示的渐进时间复杂度:

  1. 用常数1取代运行时间中左右加法常数
  2. 在修改后的运行次数函数中只保留最高阶项
  3. 如果最高阶项存在且不是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表示法)相关推荐

  1. 算法与数据结构(part1)--算法简介及大O表示法

    学习笔记,仅供参考 文章目录 算法与数据结构--基于python 数据结构和算法简介 算法引入 例题A 算法的概念 例题A的优化 算法效率的衡量 时间复杂度与大O记法 例题A的时间复杂度 如何理解大O ...

  2. 算法概念:大O表示法/小o表示法/Ω/Θ

    如果算法A需要的时间与f(n)成正比,则算法A称为f(n)阶,表示为O(f(n)).函数f(n)称为算法的增率函数(growth-rate function).该表示法使用大写字母O来表示(order ...

  3. 算法复杂度/大O方法/渐近分析法

    A Gentle Introduction to Algorithm Complexity Analysis Dionysis "dionyziz" Zindros dionyzi ...

  4. 数据结构-算法: 分配排序(基数分配排序法)

    基数排序(Radix Sort)是对箱排序的改进和推广. 1.单关键字和多关键字     文件中任一记录R[i]的关键字均由d个分量                      构成. 若这d个分量中每 ...

  5. 数据结构学习笔记:算法复杂度的度量之“大O记号”

    分析算法复杂度的非常重要的方法:大O记号!! 下面来让我们看一下到底什么是大O记号 举个例子: 用一个直尺去评价算法复杂度,上面的刻度就相当于大O记号,我们不一定要一味的强调刻度的精细程度,没有必要. ...

  6. 大O表示法(复杂度分析)

    程序 = 数据结构 + 算法 大O表示法 什么是程序?相信学过编程的人都知道,程序由数据结构和算法构成,想要写出好的的程序,首先得了解数据结构和算法.一切脱离数据结构和算法的程序设计都是耍流氓! 什么 ...

  7. 复杂度分析(大O表示法)

    复杂度分析 前文提要 本文完完全全引用极客时间的文章<数据结构与算法之美>,作者王争. 数据结构是作为程序猿绕不过的一道坎,所以萌生了学习的想法,试读了几篇文章后发现讲的很好,也有很多人订 ...

  8. 数据结构与算法——复杂度

    算法是用于解决特定问题的一系列的执行步骤.使用不同算法,解决同一个问题,效率可能相差非常大.为了对算法的好坏进行评价,我们引入 "算法复杂度" 的概念. 1.引例:斐波那契数列(F ...

  9. 大o表示法描述复杂度_时间复杂度,空间复杂度和大O表示法

    大o表示法描述复杂度 This is the first post in my series Data Structures & Algorithms. As a boot camp grad ...

最新文章

  1. 基于Spring可扩展Schema提供自定义配置支持
  2. 【百度地图API】建立全国银行位置查询系统(四)——如何利用百度地图的数据生成自己的标注...
  3. Light-Head R-CNN
  4. php补充 扩展,php补充安装扩展支持
  5. 用python阐释工作量证明(proof of work)
  6. Java高新技术笔记:反射、多线程、泛型、枚举、javaBean、代理
  7. 【数学题】男女的比例
  8. Markdown常用转义字符
  9. js本页导出Excel,下载
  10. 多叉树/图结构维护问题转线性结构——dfs序
  11. 俗话说“肩挑四两为客,帮人一日为奴”,这是什么意思?
  12. mysql 设置密码
  13. linux下高可用性群集和负载均衡群集的实现
  14. 未知错误 ID:-2147467259 操作必须使用一个可更新的查询
  15. 最全面的测试用例--web测试
  16. 湖南省计算机二级官网2020,湖南2020年3月计算机二级考试报名时间安排
  17. windows部署tensorflow serving
  18. 有趣的HTML实例(七) 注册登录界面Ⅱ(css+js)
  19. Codeforces1696 C. Fishingprince Plays With Array
  20. Hadoop2.x与Hadoop3.x的默认端口变化

热门文章

  1. 跳板机文件上传至其他服务器
  2. python 两点连线 matplotlib
  3. 招聘一周×上海 | 美团、PayPal、腾讯、小红书等 8 家公司最新内推岗位
  4. python使用requests_toolbelt库做multipart格式HTTP上传请求
  5. XMind中如何添加自定义图标
  6. 54.Python的def语句自定义函数
  7. yum安装telnet
  8. 男生因为孤独而优秀,女生因为优秀而孤独?
  9. 十个程序员必备的技术网站,感谢分享
  10. 攒一台自己的深度学习主机