程序 = 数据结构 + 算法

大O表示法

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

什么样的程序才是好的程序?好的程序设计无外乎两点,"快""省"。"快"指程序执行速度快,高效,"省"指占用更小的内存空间。这两点其实就对应"时间复杂度"和"空间复杂度"的问题。

怎样分析一个程序的时间复杂度和空间复杂度?接下来今天的主角就要登场了!"大O表示法"。"大O表示法"表示程序的执行时间或占用空间随数据规模的增长趋势。大O表示法就是将代码的所有步骤转换为关于数据规模n的公式项,然后排除不会对问题的整体复杂度产生较大影响的低阶系数项常数项。乍一看这句话可能不好理解,接下来会详细介绍怎么用"大O法"来进行时间和空间复杂度分析。

时间复杂度

时间复杂度,又称"渐进式时间复杂度",表示代码执行时间与数据规模之间的增长关系。

Talking is cheap,show me your code!(不BB,看代码!)

先来看一个简单的栗子,来分析下下面这段代码的时间复杂度:

    /*** 累加求和* @param n 数据规模 n->∞* @return*/public int sum(int n){int sum = 0;int i = 0;for (;i<n;i++){sum = sum + i;}return sum;}

上面是一个累加求和的方法,假设每条语句的执行时间为单位时间unit_time,那这个方法对于数据规模n来说,总的执行时间为多少呢?

很容易看出,第7、8两行代码都只执行一次,各为unit_time,第9、10两行代码都执行n次,各为n*unit_time,所以总的时间相加得T(n)=unit_time+unit_time+n*unit_time+n*unit_time=(2n+2)*unit_time

用f(n)来表示代码的执行次数和数据规模的关系,即f(n)=2n+2。当n趋近于无穷大时,f(n)中的常数项对于整个公式的值的影响可以忽略,同样,系数相比于数据规模n也可以忽略不计。最后变为f(n) = n,即总的执行时间T(n)与数据规模n成正比。上面的分析方法就是"大O表示法"的主要思想,用公式来表示就是:

n:数据规模,通俗点说就是函数中的那个变量n

f(n):代码总的执行次数和数据规模的关系

T(n):代码的执行时间(并不是代码实际的执行时间,这里表示代码执行时间和数据规模之间的关系)

看到这大概对大O分析法有了一定的理解吧!下面来详细介绍时间复杂度的分析方法。

1.只关注循环执行次数最多的那段代码

拿上面那个例子来说,第7、8行代码与数据规模无关,执行次数最多的在第9、10行代码,所以只需要关注循环这一部分。利用大O分析法可以知道上面累加求和例子的代码时间复杂度为O(n).

下面再来看一个栗子:

    /*** 只关注循环次数最多的那一段代码* @param n 数据规模 n->∞* @return*/public int sums(int n){int sum = 0;int sum1 = 0;int i = 0;int j = 0;for (;i<n;i++){sum = sum + i;}for(;j<2*n;j++){sum1 = sum1 + j;}return sum+sum1;}

依然拿上面累加求和这个例子,不过这次返回的是数据规模n累加和数据规模2倍累加的和。该方法中有2处循环部分,第11、12行和第14、15行。可以看出来,这两处都有循环的部分,但是下面循环执行次数比上面多。根据上面的原则,我们只需要关注循环执行次数最多的那部分代码。按照上面大O分析法可以知道,这段代码的时间复杂度为O(n).

2.加法法则(总复杂度等于量级最大的那段代码的复杂度

首先,来了解一下量级的概念。下面是一些常见的复杂度量级及其大O法的表示。

常量阶(O(1)):代码片段执行时间不随数据规模n的增加而增加,即使执行次数非常大,只要与数据规模无关,都算作常量阶。记作O(1).

按量级递增排序:常量阶O(1)) < 对数阶O(logn)  线性阶O(n) < 线性对数阶O(nlogn) < 平方阶O(n²)...立方阶O(n³)...k方阶 < 指数阶O(< 阶乘阶O(n!) 

其中,O()和O(n!)为非多项式量级,其他的为多项式量级。我们把时间复杂度为非多项式量级的算法问题叫作NP(Non-Deterministic Polynomial,非确定多项式)问题。

下面请看一段代码:

    /*** 加法法则:总复杂度等于量级最大的那段代码的复杂度* @param n 数据规模 n->∞* @return*/public int maxItem(int n){// part1: 执行1000次循环int i = 0;int sum1 = 0;for (;i<1000;i++){        sum1 = sum1 +i;}// part2: 执行n此循环int j = 0;int sum2 = 0;for (;j<n;j++){            sum2 = sum2 +j;}// part3: 嵌套执行n次循环int sum3 = 0;for (int k=0;k<n;k++){            for (int l=0;l<n;l++){sum3 = sum3 + l;}}return sum1+sum2+sum3;}

代码中有三部分,来分别分析每一部分的时间复杂度。第一部分循环执行1000次,与数据规模n无关,即使执行10000次,100000次都算作常量阶,时间复杂度为O(1)。

第二部分循环执行n次,与数据规模n成正比,时间复杂度是线性阶O(n)。

第三部分有两层循环,每层循环都执行n次,总共执行n*n=n²次,时间复杂度为平方阶O(n²)。

所以这段代码总的时间复杂度记作T(n) = O(1)+O(n)+O(n²),按照加法法则,只取最大量级的的复杂度,即整段代码的时间复杂度为O(n²)。

3.乘法法则(嵌套代码复杂度等于内外代码复杂度的乘积

依旧来看一段代码:

    /*** 外层方法* @param n 数据规模* @return*/public int outSum(int n){int i = 0;int sum = 0;for (;i<n;i++) {// 这里调用inSum()方法累加求和sum = sum + inSum(i);}return sum;}/*** 里层方法* @param n 数据规模* @return*/public int inSum(int n){int i = 0;int sum = 0;for (;i<n;i++) {sum = sum + i;}return sum;}

不难分析出,但看外层和里层循环,时间复杂度均为O(n)。二者嵌套一起就可以用到乘法法则,总的时间复杂度为O(n*n)=O(n²)。其实这里就是循环嵌套,总的执行次数为内外执行次数的乘积。

空间复杂度

空间复杂度,也称渐进空间复杂度,表示代码存储空间与数据规模之间的增长关系。

空间复杂度相对于时间复杂度来说,要简单的多了。下面看一个简单的栗子:

    /*** 空间复杂度分析* @param n 数据规模*/public void space(int n){int i = 0;int[] arr = new int[n];for (;i<n;i++) {arr[i] = i;}}

第6行申请一个空间存储变量i,由于该空间和数据规模无关,属于常量阶的空间复杂度,可忽略不计。

第7行申请一个大小为n的空间存储数组arr,空间复杂度与数据规模成正比,为O(n)。所以整段代码空间复杂度就是O(n)。

一般情况下,一个程序在机器上执行时,除了需要存储程序本身的指令、常数、 变量和输入数据外,还需要存储对数据操作的存储单元。若输入数据所占空间只取决于问题本身,和算法无关,这样只需要分析该算法在实现时所需的辅助单元即可。若算法执行时所需的辅助空间相对于输入数据而言是个常数,则称此算法为原地工作,空间复杂度为O(1)。

常用的空间复杂度就是O(1)。像O(n²)、O(n³)、O(logn)、O(nlogn)这样的空间复杂度平时都用不到。

以上为自己学习极客时间专栏王争老师的"数据结构与算法"的总结,仅供学习使用。本人新开的博客,菜鸟一枚,不正确的地方希望大家指出来,一起学习进步!

大O表示法(复杂度分析)相关推荐

  1. 渐进式复杂度分析-学习笔记

    渐进式复杂度分析 概念 目的 大O表示法 复杂度分析方法 常用复杂度级别 复杂度分析的4个概念 概念 复杂度描述的是算法执行时间(或占用空间)与数据规模的增长关系,描述了当数据量趋近于无穷大的时候,算 ...

  2. 数据结构与算法分析c++第四版_数据结构与算法 - 时空复杂度分析

    这周主要总结了时间复杂度的学习,跟小伙伴们分享下,欢迎指正. 一.为何需要分析算法复杂度 挺多同学本科都学习过数据结构和算法这门课,但是有没有想过这门课到底是解决什么问题?科学家设计这些数据结构和算法 ...

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

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

  4. 时间复杂度分析-大O表示法

    开篇词 | 从今天起,跨过"数据结构与算法"这道坎 你好,我是王争,毕业于西安交通大学计算机专业.现在回想起来,本科毕业的时候,我的编程水平其实是很差的.直到读研究生的时候,一个师 ...

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

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

  6. SEO中的十大关键词竞争度分析方法

    关键词分析在SEO中的地位是举足轻重的,其中关键词的竞争强度分析也尤为重要.关键词竞争强度,通俗来讲,也就是这个词竞争大不大,好不好做上去?可能这些大家都知道,之所以列出来,只是为了让不知道的朋友了解 ...

  7. 软件可靠性分析方法有失效模式影响分析法、严酷度分析法、故障树分析法、事件树分析法、潜在线路分析法

    研究 软件可靠性分析方法有失效模式影响分析法.严酷度分析法.故障树分析法.事件树分析法.潜在线路分析法 http://wenku.baidu.com/link?url=_XcuD0fStz39Doo5 ...

  8. 大整数的乘法(递归方程+复杂度分析)

    递归方程+复杂度分析 大整数的乘法 背景介绍 设X和Y都是n位二进制整数,现在需要计算它们的乘积XY,如果使用小学的思路设计算法,那么需要n2次乘法和n-1次加法,效率太低,那么能够设计出一种算法能够 ...

  9. 数据结构-----算法复杂度(大O表示法)

    为什么要先聊这个算法复杂度呢? 首先,我们先聊聊算法."老衲"经常听别人说起算法,但还是不太明白算法是什么. 先拽一大段概念: 算法(Algorithm)是指解题方案的准确而完整的 ...

最新文章

  1. Word中你不得不学习的几个小技巧,让你不仅玩的溜,效率也贼高!
  2. pfx证书密码怎么查询_2019成考成绩查询时间通知!忘记账号和密码怎么办?
  3. ElasticSearch logo 分布式搜索引擎 ElasticSearch
  4. C#发送邮件的实现实例解析
  5. mysql sql使用序列_SQL 使用序列
  6. 是男人就下100层【第五层】——2048游戏从源码到发布市场
  7. 常用STL整理 (施工中 2017.8.11更新)
  8. wow 私服trinitycore
  9. 软件验收测试报告报价,软件验收测试介绍和软件验收报告的费用是多少?
  10. 【Python】导入类
  11. oracle中打钩,wps文档如何在小方块里打钩?
  12. mgetnx redis_redis-cluster集群模式下使用pipeline,mget,mset批量操作
  13. k8s--基础--12.2--pod--生命周期,状态,重启策略
  14. 电信计费系列3-短信计费
  15. TensorFlow Probability 联合分布变分推断工具,估计权重的贝叶斯可信区间更简单
  16. mysql端口号3306被占用_使用pandas将excel表格数据导入到mysql中
  17. 物联网的2018:这是百花齐放的一年
  18. 【编程】工具 - Compuware 全套产品的许可文件(License.xml)
  19. 新手小白学java 编码转换流 OutputStreamWriter InputStreamReader
  20. 常见的IEEE802系列中的协议

热门文章

  1. 第五章 生活无处不数据,大数据真的能算命?
  2. Java大数据学习路线图
  3. Vue源码之用户watcher
  4. 中国机器博弈事业开拓者、CAAI 会士徐心和教授因病逝世...
  5. 结合Bootstrap实现头像上传前预览
  6. 淘宝卖家打造爆款时需要考虑到哪些重要因素?
  7. 从 Azure Databricks 访问 Azure Blob 存储
  8. 2018全国普通高校学科竞赛排行榜发布
  9. sendfile详解
  10. 别忽略国美之争的真正遗产