前言

本笔记主要记录如何分析、统计算法的执行效率和资源消耗。

必须学会分析复杂度分析。

李柱明博客:https://www.cnblogs.com/lizhuming/p/15487271.html

复杂度

复杂度分为:

  1. 时间复杂度。关联到执行效率。

    • 时间复杂度的全称是 渐进时间复杂度,表示算法的执行时间与数据规模之间的增长关系。
  2. 空间复杂度。关联到资源消耗。

    • 空间复杂度全称就是渐进空间复杂度,表示算法的存储空间与数据规模之间的增长关系。

分析方法

大 O 复杂度表示法

先说结论:

  • 大 O 复杂度表示方法只是表示一种变化趋势。
  • 忽略掉公式中的常量、低阶、系数,只需要记录一个最大阶的量级就可以了。
  • 多、加法和乘法规则。

例子-评估累加和的各种算法执行效率

算法 1(for 循环):
int cal(int n)
{
int sum = 0;
int i = 1;
for (; i <= n; ++i)
{
sum = sum + i;
}
return sum;
}
  • 从 CPU 角度看:

    • 重复类似的操作:读数据-运算-写数据。
    • 假设每行代码执行事件都为 unit_time。(粗略估计)
    • 代码中执行的时间为:T(n) = (2+3n)*unit_time。
  • 结论:所有代码的执行时间 T(n) 与每行代码的执行次数成正比。

算法 2(嵌套 for 循环):
int cal(int n)
{
int sum = 0;
int i = 1;
int j = 1;
for (; i <= n; ++i)
{
j = 1;
for (; j <= n; ++j)
{
sum = sum + i * j;
}
}
}
  • 代码中执行时间为:T(n) = (3+3n+3n²)*unit_time=3(n²+n+1)*unit_time。
  • 所有代码的执行时间 T(n) 与每行代码执行的次数成正比。

大 O 表示

T(n) = O(f(n))

  • 上面算法 1 中的大 O 表示法为:T(n) = O(2+3n)。

  • 上面算法 2 中的大 O 表示法为:T(n) = O(3(n²+n+1))。

  • 大 O 表示法不是表示代码真正的执行时间,而是表示代码执行时间随数据规模增长的变化趋势。

    • 即是时间复杂度。

当 n 很大时,公式中的低阶、常量、系数三部分并不左右增长趋势,所以都可以忽略。

只需要记录一个最大量级就可以了,如果用大 O 表示法表示刚讲的那两段代码的时间复杂度,可记为:

  • T(n) = O(n);
  • T(n) = O(n²)。

时间复杂度分析

当了解了大 O 表示法后,就可以用来分析时间复杂度了。

三个实用的方法:

  1. 只关注循环执行次数最多的一段代码。(多)
  2. 加法法则:总复杂度等于量级最大的那段代码的复杂度。(大)
  3. 乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积。(嵌套:积)

关注执行最多的一段代码

以上面算法 1 为例:

  • 前面两行代码为常量级别,忽略。

  • 3n 中的系数也可忽略。

  • 结论:时间复杂度为 O(n)

算法 2 的时间复杂度就是 O(n²)

加法规则

加法法则:总复杂度等于量级最大的那段代码的复杂度。

  • 公式:T(n)=T1(n)+T2(n)=max(O(f(n)), O(g(n))) =O(max(f(n), g(n)))。

若上面算法 1 和算法 2 出现在同一个代码段中是,其时间复杂度之和为 O(n)+O(n²)。

总的时间复杂度就是取最大量级: O(n²)。

乘法规则

乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积。

  • 公式:T1(n)=O(f(n)),T2(n)=O(g(n));那么 T(n)=T1(n)T2(n)=O(f(n))O(g(n))=O(f(n)*g(n))。

例子:

  • 时间复杂度:T(n) = T1(n) * T2(n) = O(n*n) = O(n²)。
int func(int n)
{
int sum = 0;
int i = 1;
for (; i < n; ++i)
{
sum = sum + i;
}
return sum;
} int cal(int n)
{
int ret = 0;
int i = 1;
for (; i < n; ++i)
{
ret = ret + func(i);
}
}

常见时间复杂度

常见时间复杂度量级如图:

这些复杂度量级可分为:

  • 多项式量级:

    • 常量阶:O(1)
    • 对数阶:O(logn)
    • 线性阶:O(n)
    • 线性对数阶:O(nlogn)
    • k 次方阶:O(nk)(注意:这里的 k 为 k 次方)
  • 非多项式量级

    • O(2n);(注意:这里的 n 为 n 次方)
    • O(n!)。
    • 说明:当数据规模 n 越来越大时,非多项式量级算法的执行时间会急剧增加,求解问题的执行时间会无限增长。所以,非多项式时间复杂度的算法其实是非常低效的算法。

常量阶 O(1)

O(1) 只是常量级时间复杂度的一种表示方法,并不是指只执行了一行代码。

大牛总结:(常量级记作 O(1))

  • 只要代码的执行时间不随 n 的增大而增长,这样代码的时间复杂度我们都记作 O(1)。
  • 或者说, 一般情况下,只要算法中不存在循环语句、递归语句,即使有成千上万行的代码,其时间复杂度也是 Ο(1) 。

对数阶 O(logn)、O(nlogn)

i=1;
while (i <= n)
{
i = i * 2;
}

时间复杂度分析过程:

  • 多:第 4 行代码执行次数最多。那就算出第四行执行的次数。

  • 得 x = log2n 即时间复杂度为 O(log2n)。也就是 O(logn)。

  • 不管底数为何值,都把这类对数阶的时间复杂度记为 O(logn)。理由:

    • log3n = log32 * log2n。对应时间复杂度为:O(log3n) = O(C * log2n)。
    • 按前面学的系数可忽略:O(log3n) = O(log2n)。
    • 既然不同底数都可以转化,那就直接使用 O(logn) 来标记对数阶。

而对于 O(nlogn) 就是一段时间复杂度为 O(logn) 的代码段被执行了 n 次。

多参数阶 O(m+n)、O(m*n)

分析代码的时间复杂度由两个以上数据的规模来决定。

以下以两个数据规模决定为基础。

int cal(int m, int n)
{
int sum_1 = 0;
int i = 1;
for (; i < m; ++i)
{
sum_1 = sum_1 + i;
} int sum_2 = 0;
int j = 1;
for (; j < n; ++j)
{
sum_2 = sum_2 + j;
}
return sum_1 + sum_2;
}
  • 其时间复杂度为:O(m+n)
  • 对于加法规则(变了):T1(m) + T2(n) = O(f(m) + g(n))。
  • 对于乘法规则(不变):T1(m)*T2(n) = O(f(m) * f(n))。

空间复杂度分析

空间复杂度。关联到资源消耗。

  • 空间复杂度全称就是渐进空间复杂度,表示算法的存储空间与数据规模之间的增长关系。

使用大 O 表示法,和时间复杂度一样,只是分析的数据规模 n 由时间度量改为空间度量。

小结

复杂度也叫渐进复杂度,包括时间复杂度和空间复杂度,用来分析算法执行效率与数据规模之间的增长关系。

通常越高阶复杂度的算法,执行效率越低。

常见的复杂度并不多,从低阶到高阶有:O(1)、O(logn)、O(n)、O(nlogn)、O(n2 )。

【数据结构&算法】02-复杂度分析之执行效率和资源消耗的更多相关文章

  1. 《数据结构与算法之美》 <01>复杂度分析(上):如何分析、统计算法的执行效率和资源消耗?

    我们都知道,数据结构和算法本身解决的是“快”和“省”的问题,即如何让代码运行得更快,如何让代码更省存储空间.所以,执行效率是算法一个非常重要的考量指标. 那如何来衡量你编写的算法代码的执行效率呢?这里 ...

  2. Chapter3 复杂度分析(上):如何分析,统计算法的执行效率和资源消耗

    数据结构解决的问题:“快” + “省”,即为时间,空间复杂度分析 1:为什么需要复杂度分析? 因为通过统计手段分析的结果受到两个因素的影响,一:测试结果非常依赖测试环境,二:测试结果受数据规模的影响很 ...

  3. 重拾算法之复杂度分析(大O表示法)

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

  4. 三行代码实现.NET MVC统计显示页面的执行时间 超简单的实现方法 分析页面执行效率

    三行代码实现.NET MVC统计显示页面的执行时间 超简单的实现方法 分析页面执行效率    博客页脚处添加了页面执行时间统计显示,如下图所示,也可以直接查看网页页脚处. 实现方法非常简单,只需三行代 ...

  5. 《数据结构与算法之美》 <02>复杂度分析(下):浅析最好、最坏、平均、均摊时间复杂度?

    上一节,我们讲了复杂度的大 O 表示法和几个分析技巧,还举了一些常见复杂度分析的例子,比如 O(1).O(logn).O(n).O(nlogn) 复杂度分析.掌握了这些内容,对于复杂度分析这个知识点, ...

  6. 数据结构与算法 java描述 第一章 算法及其复杂度

    目录 数据结构与算法 java描述 笔记 第一章 算法及其复杂度 算法的定义 算法性能的分析与评价 问题规模.运行时间及时间复杂度 渐进复杂度 大 O 记号 大Ω记号 Θ记号 空间复杂度 算法复杂度及 ...

  7. 八大排序算法详解(动图演示 思路分析 实例代码java 复杂度分析 适用场景)

    一.分类 1.内部排序和外部排序 内部排序:待排序记录存放在计算机随机存储器中(说简单点,就是内存)进行的排序过程. 外部排序:待排序记录的数量很大,以致于内存不能一次容纳全部记录,所以在排序过程中需 ...

  8. 八大排序算法——希尔(shell)排序(动图演示 思路分析 实例代码java 复杂度分析)

    一.动图演示 二.思路分析 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序:随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止. 简单插 ...

  9. 八大排序算法——插入排序(动图演示 思路分析 实例代码java 复杂度分析)

    一.动图演示 二.思路分析 例如从小到大排序: 1.  从第二位开始遍历, 2.  当前数(第一趟是第二位数)与前面的数依次比较,如果前面的数大于当前数,则将这个数放在当前数的位置上,当前数的下标-1 ...

随机推荐

  1. navicat导出DDL语句

    工作中有的时候需要将某个库中的表.视图.函数.存储过程等创建语句导出,又不需要表中的数据. 方法一:需要拷贝的创建语句条数不多,可以选择直接拷贝DDL语句 方法二:使用Navicat的备份功能

  2. HTML 网页开发、CSS 基础语法——二.互联网原理

    1. 互联网的运行过程 ①用户通过输入网址,发送一个HTTP请求到服务器中去,服务器里面存储了程序员上传的所有网页文件. ② 服务器一旦接收到请求,就会将我们所有的相关网页文件,回传到客户端,通过HT ...

  3. P4643-[国家集训队]阿狸和桃子的游戏【结论】

    正题 题目链接:https://www.luogu.com.cn/problem/P4643 题目大意 给出\(n\)个点\(m\)条边的无向图,两个人轮流选择一个未被选择的点加入点集. 然后每个人的 ...

  4. YbtOJ#943-平方约数【莫比乌斯反演,平衡规划】

    正题 题目链接:http://www.ybtoj.com.cn/contest/122/problem/3 题目大意 \(S(i)\)表示\(i\)的约数个数,\(Q\)次询问给出\(n,m\)求 \ ...

  5. 基于Processing图像序列处理保存导出的流程梳理

    做一个基于processing的图像序列处理保存导出的流程梳理.本案例没有什么实质性的目的,仅为流程梳理做演示. 准备 把需要处理的影像渲染成序列图片,可以在PR中剪辑并导出PNG序列[格式倒是没什么 ...

  6. 【MySQL数据库】MySQL5.7安装与配置、可视化工具安装和破解

    软件下载 Mysql5.7地址:https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.19-winx64.zip 安装步骤 下载后会得到zip ...

  7. SpringBoot-邮件任务

    邮件发送,在我们的日常开发中,也非常的多,Springboot也帮我们做了支持 邮件发送需要引入spring-boot-start-mail SpringBoot 自动配置MailSenderAuto ...

  8. Linux系统安装MySql5.7并通过sql脚本导入数据

    为了下载到的MySQL版本和目标系统相互兼容,在开启之前,最好了解目标系统的相关信息. 查询系统版本: cat /etc/issue 查看系统位数 getconf LONG_BIT 选择MySQL 根 ...

  9. SpringCloud升级之路2020.0.x版-28.OpenFeign的生命周期-进行调用

    本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 接下来,我们开始分析 OpenFeign 同步环境下的生命周期的第二部分,使用 Synch ...

  10. 【集成学习】:Stacking原理以及Python代码实现

    Stacking集成学习在各类机器学习竞赛当中得到了广泛的应用,尤其是在结构化的机器学习竞赛当中表现非常好.今天我们就来介绍下stacking这个在机器学习模型融合当中的大杀器的原理.并在博文的后面附 ...