算法的复杂性

news2024/9/20 14:32:59

通常情况下,一个问题可能对应有多种解决方案,每种解决方案都是一种算法。因此,我们可能经常需要做一件事:从众多算法中挑选出一个最好的算法。所谓“最好”的算法,即最适合当前场景使用的算法。

不同的应用场景,挑选算法的侧重点也有所不同。多数情况下,挑选算法主要考虑以下两个因素:

  • 算法的执行效率:一个算法的执行时间越短,执行效率就越高;
  • 占用存储空间的大小:有些机器的存储空间很少,因此挑选算法时,应优先选择所需存储空间小的算法。

在适合特定场景的前提下,算法的执行效率越高、占用的存储空间越小,算法就越好。

判断算法的“好坏”,有以下两种方式:

  1. 事后统计:将各个算法都编写成可运行的程序,然后交给计算机执行,记录程序的运行时间和占用的存储空间的实际大小,从而挑选出最好的算法;
  2. 预先估算:根据算法包含的各个步骤,估算出算法的运行时间和占用存储空间的大小。通过比较各个算法的估算值,挑选出最好的算法。


大多数情况下,我们选择第 2 种方式。原因很简单,将众多算法一一实现的工作量太大,得不偿失。此外,不同计算机的软、硬件环境不同,即便使用同一台计算机,不同时间段的运行环境也不相同,事后统计的结果会受到各种因素的影响,不一定准确。

我们习惯用时间复杂度表示一个算法的运行时间,用空间复杂度表示算法占用存储空间的大小。

时间复杂度

时间复杂度用来表示算法运行所需要的时间。

计算一个算法的时间复杂度,需要经历以下几个步骤:

1) 统计算法中各个步骤的执行次数

我们知道,算法是有限的执行步骤的集合,每个算法都可以用伪代码来表示。因此,一个算法的执行时间可以用伪代码中所有指令执行次数的总和来表示。

举个例子,计算从 1 加到 n 的和并输出。如下用伪代码的形式描述了一个可以解决此问题的算法:

sum <- 0                      // 将 0 赋值给 sum,执行 1 次
for i <- 1 to n+1:         // i 从 1 循环到 n+1(i<n+1),执行 n+1 次
    sum <- sum+i;         // 每次循环将 sum+i 的值赋值给 sum,执行 n 次
print sum                     // 输出 sum 的值,执行 1 次

整段伪代码共有 4 条指令,它们的执行次数分别为 1 次、n+1 次、n 次、1 次,总的执行次数为 2*n+3 次。因此,我们可以用 2*n+3 表示该算法的执行时间,其中 n 是一个变量。这意味着,算法的执行时间和 n 的大小有直接的关系。

显然,通过此方法统计得到的算法的执行时间,并不是固定值,更多时候得到的是类似 2*n+3、n2+2*n+3 这样的表达式。这就产生一个问题,如何通过比较不同的表达式挑选出效率最高的算法呢?

2) 大 O 记法比较表达式的大小

某个问题对应有 3 种算法,它们各自的执行时间分别为 10、2*n+3、n2+2*n+3,如何比较它们的大小呢?

很简单,我们只需要确定 n 的值,就可以轻松比较出它们的大小。例如当 n =1 时,它们的大小关系是 10 > n2+2*n+3 > 2*n+3,因此 2*n+3 对应算法的执行效率最高;再比如 n =10 时,它们的大小关系为 n2+2*n+3 > 2*n+3 > 10,因此 10 对应算法的执行效率最高。

大多数场景下,我们都遵循这样的比较原则:假设 n 的值无限大,比较各个表达式的大小,从而找到执行效率最高的算法。仍以 10、2*n+3、n2+2*n+3 为例,当 n 的值趋于无限大时,显然 10 对应算法的执行效率最高。

对于累加项个数较少的表达式,我们很容易就能比较它们的大小,但如果算法的执行时间是类似 3*n+2*n2+4+logn+... 这样的表达式,比较起来会有些困难。针对这种情况,我们可以依照如下规则对表达式进行简化:

  1. 去掉表达式中所有的加法常数项,比如 3*n2+2*n+3 简化为 3*n2+2*n。当 n 值无限大时,常数项对整个表达式的值的影响可以忽略不计;
  2. 去掉表达式中指数较低的加法项,例如 3*n2+2*n 简化为 3*n2。当 n 无限大时,n2 的值远远大于 n,此时 n 值的变化对 n2 的影响可以忽略不计。
  3. 去掉 n 的系数,例如 3*n2 简化为 n2。当 n 无限大时,系数对整个表达式值的影响可以忽略不计。


根据此规则,我们就将 3*n2+2*n+3 简化为了 n2。同理,我们可以将 3*n+2*n2+4+logn 简化为 n2。通过简化表达式,降低了表达式的复杂度,便于我们比较各个表达式的大小关系。

此外,为了避免人们随意使用 a、b、c 等字符来表示算法的运行时间,大家逐渐达成了一种共识,即采用大 O 记法(注意,是大写的字母 O,不是数字 0)表示算法(程序)的运行时间,又称为算法的时间复杂度。

发展至今,大 O 记法已为大多数人所采纳,表示方法也很简单,格式如下:

O(频度)

其中,频度就是简化之后的表达式。注意,对于执行时间为常数的(例如上面的 10),算法的时间复杂度用 O(1) 表示。

例如,n2+2*n+3 对应算法的时间复杂度为 O(n2)。如下列举了常用的几种时间复杂度,以及它们之间的大小关系(值越小,算法的运行效率越高):

O(1)常数阶 < O(logn)对数阶 < O(n)线性阶 < O(n2)平方阶 < O(n3)(立方阶) < O(2n) (指数阶)

空间复杂度

算法的空间复杂度,指的是该算法执行过程占用的存储空间的大小。

根据算法编写出的程序,执行过程中占用的存储空间大致可分为以下几部分:

  • 程序代码本身所占用的存储空间;
  • 程序中如果需要输入输出数据,也会占用一定的存储空间;
  • 程序在运行过程中,可能会临时申请额外的存储空间。


程序自身所占用的存储空间取决于其包含的代码量,如果要压缩这部分存储空间,只需要精简程序代码即可。程序运行过程中输入输出的数据往往由实际问题而定,也就是说,程序输入输出所占用的存储空间和选用的算法之间,没有必然的联系。

因此,比较算法占用的存储空间,针对的往往是算法执行过程中额外申请的存储空间的大小。不同的算法,其执行时额外申请的存储空间的大小也有所不同。

举个例子,如下是一段伪代码:

输入 n               // 输入 n 值
for i<-1 to n     // 将从 1 到 n 的值存储在 A 数组中
    A[i] <- i        //  将 i 存储在 A 数组中第 i 个元素的位置

可以看到,根据 n 的值,伪代码中会额外申请可存放 n 个元素的存储空间。

和时间复杂度一样,算法的空间复杂度也采用大 O 记法表示:

  • 如果算法中额外申请的存储空间和输入值无关,则算法的空间复杂度就为 O(1);
  • 如果随着输入值 n 的增大,算法申请的存储空间成线性增长,则程序的空间复杂度用 O(n) 表示;
  • 如果随着输入值 n 的增大,程序申请的存储空间成 n2 关系增长,则程序的空间复杂度用 O(n2) 表示;
  • 如果随着输入值 n 的增大,程序申请的存储空间成 n3 关系增长,则程序的空间复杂度用 O(n3) 表示;
  • 等等。


以上面的这段伪代码为例,随着 n 值的增大,A[1 ... n] 申请的存储空间也会增加,n 增大的速率和额外申请空间的速率之间呈线性关系,因此这部分伪代码的空间复杂度为 O(n)。

多数实际场景中,一个好的算法往往更注重的是时间效率,空间复杂度只要在一个合理的范围内即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1202991.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IT 基础架构管理需要了解的信息

各行各业的现代组织不断面临创新和扩展的压力。就在十多年前&#xff0c;一个组织可以争取时间&#xff0c;在投资新技术时保持保守&#xff0c;同时仍然保持竞争优势&#xff0c;快进到今天&#xff0c;随着商业实践的变化和新技术的不断涌现&#xff0c;商业和技术领域变得更…

瑞利长度(Rayleigh length)

瑞利长度 Rayleigh length 在光学&#xff0c;特别是激光学中&#xff0c;我们设鞍腰部&#xff08;如图中所示的最低处&#xff09;为A&#xff0c;其横截面面积为a&#xff0c;沿光的传播方向&#xff0c;当横截面面积因为散射达到2a时&#xff0c;我们设此处为B&#xff0c;…

Mysql-表的结构操作

1.创建表 CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引擎 ; 说明&#xff1a; field 表示列名 datatype 表示列的类型 character set 字符集&#xff0c;如果没有指定字…

从0到0.01入门React | 003.精选 React 面试题

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

天津火爆python培训机构从哪里入手?

Python不仅被应用在职场办公中&#xff0c;还被大型互联网公司应用于大型后端开发&#xff0c;随着大数据领域的高速发展&#xff0c;这门高效的编程语言逐渐成为处理数据的最佳编程语言之一。 Python培训班优势 系统性学习&#xff1a;Python培训班会提供结构化的课程体系&a…

SAP系统供应商预付款请求和预付账款业务

最近搞清帐&#xff01; 在SAP中处理客户或供应商的预收/预付款相关业务流程操作说明, 首先由业务部门(销售或采购)下达销售/采购订单,同时基于订单提交预收/预付申请,客户/供应商款项到账时,由财务部门在SAP中勾选申请单来收付款;最后在财务转应收/应付转发票时自动核销。预付…

Notepad++,搜索窗口独立后,恢复

双击一下find result框&#xff0c;恢复到原来的模式。

腾讯待办停运后怎么办呢?导出的ics文件怎么打开查看

待办类工具在日常工作中的应用是比较广泛的&#xff0c;很多人会选择使用待办软件记录备忘事项&#xff0c;其中一些提醒类的工具是比较广泛使用的。腾讯待办属于一款待办事项和日程管理工具&#xff0c;它通常是以微信小程序的形式&#xff0c;为大家提供时间管理规划&#xf…

做一个Springboot文章分类模块

目录 文章分类 1、新增文章分类 前言 代码编写 测试 2、 文章分类列表 前言 代码编写 测试 3、获取文章列表详情 前言 代码实现 测试 4、更新文章分类 前言 代码实现 测试 5、删除文章分类 前言 代码实现 测试 分页查询 文章列表条件分页 前言 代码编…

晶圆代工产能利用率下降,降价大战一触即发 | 百能云芯

晶圆代工行业正面临产能利用率的重大挑战&#xff0c;据悉&#xff0c;联电、世界先进和力积电等主要代工厂纷纷降低明年首季的报价&#xff0c;幅度高达两位数百分比&#xff0c;项目客户降幅更高达15%至20%&#xff0c;各大晶圆代工厂深陷产能利用率六成保卫战。 晶圆代工降价…

Outlook关闭过去事件的提醒

Outlook关闭过去事件的提醒 故障现象 最近Outlook中推出的新功能让我们可以选择自动关闭过去事件的提醒。 目前这个功能暂时只向当月通道的Office 365 订阅者发布。 这些用户升级到1810版本后&#xff0c;可以在不想收到已发生事件提醒的时候通过下面的步骤自动忽略过去事件…

将按键放到输入框内:

如何将将Button放到输入框内&#xff1f; 效果图&#xff1a; 步骤如下&#xff1a; button 外围用template 包裹一层 <template #suffix v-if"row.WorkerRole TPM"> <el-inputtype"text"v-model"row.JobNumber"placeholder"…

期中成绩这样发

数字化时代&#xff0c;成绩查询系统已经成为学校里不可或缺的一部分。老师们需要一种方便、快捷、准确的方式来发布和查询成绩&#xff0c;而学生们则需要一种安全、可靠的方式来获取自己的成绩。那么&#xff0c;如何实现这一目标呢&#xff1f;我来给大家介绍几种简单实用的…

【STM32】定时器+基本定时器

一、定时器的基本概述 1.软件定时器原理 原来我们使用51单片机的时候&#xff0c;是通过一个__nop()__来进行延时 我们通过软件的方式来进行延时功能是不准确的&#xff0c;受到很多不确定因素。 2.定时器原理&#xff1a;计数之间的比值 因为使用软件延时受到影响&#xff0c…

RK3568驱动指南|第七期-设备树-第66章of操作函数实验:获取设备树节点

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

正点原子嵌入式linux驱动开发——Linux ADC驱动

在之前的笔记中&#xff0c;学习了如何给ICM20608编写IIO驱动&#xff0c;ICM20608本质就是ADC&#xff0c;因此纯粹的ADC驱动也是IIO驱动框架的。本章就学习一下如何使用STM32MP1内部的ADC&#xff0c;并且在学习巩固一下IIO驱动。 ADC简介 ADC ADC&#xff0c;Analog to D…

里氏代换原则

package com.jmj.principles.dmeo2.after;/*** 四边形接口*/ public interface Quadrilateral {double getLength();double getWidth();}package com.jmj.principles.dmeo2.after;/*** 长方形类*/ public class Rectangle implements Quadrilateral{private double length;priv…

(附源码)基于SSM旅行社网站-计算机毕设 90030

SSM旅行社网站 摘 要 旅游业是一个信息密集型产业&#xff0c;传统的旅游景点门票售卖受到技术和人力的限制&#xff0c;旅行社网站则可以建立景区与游客之间的有效通道&#xff0c;能更好的满足游客便捷旅游的需求。旅行社网站的设计是基于SSM框架、Mysql数据库、JSP技术、Aja…

立体库堆垛机水平电机输出控制程序功能

###############水平电机输出控制程序################# #############水平变频器输出控制程序################# *******************水平速度曲线建立*********************** 列距离差值&#xff0c;建立与速度的关系式&#xff1a;VX/k MW220为K系数 水平速度控制K系数 列…

EDA实验-----3-8译码器设计(QuartusII)

目录 一. 实验目的 二. 实验仪器 三. 实验原理及内容 1.实验原理 2.实验内容 四&#xff0e;实验步骤 五. 实验报告 六. 注意事项 七. 实验过程 1.创建Verilog文件&#xff0c;写代码 ​编辑 2.波形仿真 3.连接电路图 4.烧录操作 一. 实验目的 学会Verilog HDL的…