以Python程序为例介绍算法复杂度的估算

news2024/10/1 21:33:50

文章目录

  • 概念介绍
  • 时间复杂度估算
  • 空间复杂度估算


引自同一作者百家号文章:「Python语言进阶」算法复杂度是什么?如何估算?

概念介绍

算法,可以理解为解决问题的方法和思路,不是一定得有代码的才叫算法,它是可以独立存在的,代码只是算法实现的一种载体。而我们评价算法的性能,也就是评价一个算法好不好,主要是评估算法的复杂度。

算法复杂度:分为(渐进)时间复杂度和(渐进)空间复杂度。这也是考量算法消耗计算机最重要的两种资源(时间、寄存器空间)的情况。时间复杂度:可以简单理解为电脑的基本运算的执行次数;空间复杂度:可以理解为电脑实现这个算法的过程中所开辟的存储空间大小。

算法分析一般指的复杂度分析,包括时间和空间两方面,其目的在于选择合适的算法和改进算法。那我们如何估算或表示算法的复杂度?答案是:大O法

O ( g ( n ) ) O(g(n)) O(g(n))来表示算法估算的渐进复杂度, f ( n ) f(n) f(n)表示实际复杂度, g ( n ) g(n) g(n) f ( n ) f(n) f(n)成正比, n n n 表示算法输入的数据规模。这里和前面都提到的“渐进”,指的是当输入数据规模趋近于无穷大的情况下算法的复杂度,它反映的是算法复杂度随着输入数据规模增加而提升的速度。

时间复杂度估算

刚才说,算法执行基本运算的次数用来描述时间复杂度,而现实中还会遇见说用执行时间来描述复杂度的,用执行时间来做性能分析的。而且Python有 timeit 库用来分析程序的系统运行时间,如下示例:

import time
from timeit import Timer


def func():
    s = 0
    for i in range(1000):
        s += i


# Timer(函数名_字符串,运行环境_字符串)
test = Timer('func()', 'from __main__ import func')
# timeit(1),运行1次,参数省略则默认运行1000,000次
print(test.timeit(1))

在实际中,用执行时间来表示时间复杂度是很方便的,但因为执行时间的长短的影响因素很多,包括运行环境、算法随机性、算法和输入数据的适配性等,使得用不同条件下得到的执行时间来估算时间复杂度的做法不完全可靠。

而另一个对比的方式就是用 “大O法” 进行渐进复杂度的估算,通过估算超大规模下算法执行次数的增长速度,来评估算法效率,这种估计不受程序执行环境的影响。

先来看用 “大O法“ 计算时间复杂度的几条规则:

  1. 用常数1等价替代不受数据规模影响的基本操作。如加法、赋值、打印等基本操作,它们在计算机中的执行时间是个极短的常数,而程序中的这部分与输入规模无关的操作,则可以统一为执行了1次;
  2. 嵌套循环按乘法计算。如果有个两层循环,一层是循环 n n n 次,另一层循环了 m m m 次,且循环内的执行代码都只是基本操作,那这个循环操作的复杂度为 n × m n\times m n×m;在算法设计时尽量不要用太多层循环;
  3. 分支操作按复杂度最大的分支进行计算,无特殊说明情况下,分支操作都是考虑最坏情况下的复杂度;
  4. 只保留最高次项,并去除常数系数,前面说的 g ( n ) g(n) g(n) f ( n ) f(n) f(n)成正比就很好理解了,举个例子, f ( n ) = 2 l o g n + 100 f(n)=2logn+100 f(n)=2logn+100,只保留最高次项,并去除常数系数,最后复杂度写为 O ( l o g n ) O(logn) O(logn)

时间复杂度常见到的 l o g n logn logn 是以 2 为底 n n n 的对数

如下是时间复杂度为 O ( 1 ) , O ( l o g n ) , O ( n ) O(1),O(logn),O(n) O(1),O(logn),O(n)的例子的代码:

# O(1),不含循环
def o1(n):
    return n+n*3
    
# O(logn),函数执行了logn次循环
def o_log_n(n):
    i = 1
    while i<n:
        i *= 2
    return i
    
# O(n),函数循环了n次
def o_n(n):
    count = 0
    for i in range(n):
        count += i
    return count

那么问题来了:如果既有分支又有循环,那复杂度又要怎么估算呢?

f ( n ) f(n) f(n) 来说很简单,把所有操作的复杂度加起来就行。但对于 O ( ) O( ) O() 来说,只保留其中主导的那一项。例如 f ( n ) = n l o g n + n f(n)=nlogn+n f(n)=nlogn+n,则复杂度估算为 O ( n l o g n ) O(nlogn) O(nlogn)。因为随着数据规模 n n n 趋近于无穷, n l o g n nlogn nlogn 起到主导作用,另外一项 + n +n +n 相对来说对复杂度的贡献不显著。当然,这里的默认前提是用同一个 n n n 的时间复杂度。又例如, f ( n , m ) = n l o g n + n + m f(n,m)=nlogn+n+m f(n,m)=nlogn+n+m,复杂度估算则为 O ( n l o g n + m ) O(nlogn+m) O(nlogn+m)

常见的大O时间复杂度曲线的高低排序如下,纵坐标表示操作的执行次数,横坐标表示输入数据的规模。
在这里插入图片描述
排序: O ( 1 ) < O ( l o g n ) < O ( n ) < O ( n l o g n ) < O ( n 2 ) < O ( 2 n ) < O ( n ! ) O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)<O(2^n)<O(n!) O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(2n)<O(n!)

空间复杂度估算

相比于时间复杂度,空间复杂度是很容易计算出来,其实就是算法在执行过程中,新开辟了多少用来存放变量值的存储空间,这个空间的大小即空间复杂度。同样的,存储一个值的空间看成是1(固定大小的空间),存储一个列表的空间为列表的长度,而变量的重新赋值不会改变空间复杂度。

空间复杂度的估算也是用 “大O法”,且遵循时间复杂度的估算规则,描述的是空间复杂度随数据规模 n n n 增大的渐进增速。

举个空间复杂度为 O ( 1 ) O(1) O(1) 的例子:

# O(1),每次循环都只改变原有变量值
def o1(n):
    count = 0
    for i in range(n):
        count += i
    return count

如上面的代码,运行函数只新开辟了 count 这个变量,而循环并没有分配新的空间给变量,只是在原有数的基础上进行修改。当然,辅助变量 i 也算,但是根据估算规则, O ( 2 ) O(2) O(2)最后也等价于 O ( 1 ) O(1) O(1)

此外,还有种常见的操作叫做递归,即函数自己调用自己。如下面空间复杂度为 O ( n ) O(n) O(n) 的递归例子:

def sum_(n):
    if n == 0:
        return n # 递归一定要有的中断程序
    return n+sum_(n-1)

假设 n = 10 n=10 n=10,当计算 s u m ( 10 ) sum(10) sum(10) 的时候,需要先计算 s u m ( 9 ) sum(9) sum(9),计算 s u m ( 9 ) sum(9) sum(9) 需要先计算 s u m ( 8 ) sum(8) sum(8)…在整个递归调用过程中,被调用的函数依次被压入到系统栈中(先进后计算),而这些一层层的调用状态都需要占用一定空间。换言之,递归的空间复杂度取决于递归的深度。

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

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

相关文章

每日汇评:黄金的市场注意力转向央行和地缘政治

金价从2000美元附近的数周低点反弹&#xff1b; 到目前为止&#xff0c;黄金的进一步巩固当前价格是当前的主题&#xff1b; 地缘政治、宏观数据和央行是本周的主导市场情绪&#xff1b; 黄金价格设法恢复了平衡&#xff0c;扭转了本周开始时的负面走势&#xff0c;从关键争夺区…

AI数据模型支撑下,鼎捷「预测透镜」如何助力汽配厂商浙江华工提质增效?

关于【浙江华工】 浙江华工汽车零部件有限公司&#xff08;以下简称“华工”&#xff09;成立于1987年&#xff0c;位于“中国汽摩配之都”浙江省瑞安塘下镇鲍七工业区&#xff0c;是一家集汽车发动机用冷却水泵和机油泵研发、制造、销售于一体的民营股份制企业。 近些年来&…

六种pdf在线转换工具了解一下-轻松应对pdf转换

PDF文件是我们工作中经常需要使用到的一种文件格式。然而&#xff0c;有时候我们可能需要将PDF文件转换成其他格式以满足特定的需求。为了帮助大家解决这个问题&#xff0c;本文将介绍六种实用的PDF在线转换工具&#xff0c;让你轻松完成各种文件格式的转换。 一、迅捷PDF转换器…

【代码随想录算法训练营第二十四天|回溯算法的理论基础、77. 组合】

代码随想录算法训练营第二十四天|回溯算法的理论基础、77. 组合 回溯算法的理论基础77. 组合 回溯算法的理论基础 这里我觉得《代码随想录》和y总的课都比较好了 《代码随想录》 &#xff1a; https://programmercarl.com/0077.%E7%BB%84%E5%90%88%E4%BC%98%E5%8C%96.html#%E5…

代理IP助力云函数实现更高效的网络通信

一、前言 云计算的出现使得无服务器计算成为可能&#xff0c;例如云函数。云函数是一种无需管理服务器的计算服务&#xff0c;能够根据需求自动伸缩&#xff0c;并能处理网络请求。然而&#xff0c;云函数常常受限于网络通信速度问题&#xff0c;特别是面对大量请求时。为了提…

【JavaEE进阶】 关于⽇志框架(SLF4J)

文章目录 &#x1f333;SLF4j&#x1f332;⻔⾯模式(外观模式)&#x1f6a9;⻔⾯模式的定义&#x1f6a9;⻔⾯模式的优点 &#x1f343;关于SLF4J框架&#x1f6a9;不引⼊⽇志⻔⾯&#x1f6a9;引⼊⽇志⻔⾯ ⭕总结 &#x1f333;SLF4j SLF4J不同于其他⽇志框架,它不是⼀个真正…

MySQL TINYINT(1)和TINYINT(2)有什么区别?

文章目录 1.直接建表2.查询数据3.总结 身为程序员&#xff0c;拿事实说话拿代码说话最直观了&#xff0c;show the code 1.直接建表 CREATE TABLE tinyinttest (id int NOT NULL,a TINYINT(1) NOT NULL DEFAULT 0,b TINYINT(2) NOT NULL DEFAULT 0,c TINYINT(1) ZEROFILL NOT…

【Docker】部署和运行青龙面板:一个支持python3、javaScript、shell、typescript 的定时任务管理面板

引言 青龙面板是一个支持python3、javaScript、shell、typescript 的定时任务管理面板。 步骤 拉取镜像 从 Docker Hub 上拉取最新的 “qinglong” 镜像。 docker pull whyour/qinglong:latest启动容器 使用刚刚拉取的镜像来启动一个新的 Docker 容器。 docker run -dit \-v…

基于SpringBoot的高校学科竞赛平台管理系统

基于SpringBoot的高校学科竞赛平台管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatis工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 前台界面 管理员界面 教师界面 学生界面 摘要 本文详细介绍了一款基于…

【BERT】详解

BERT 简介 BERT 是谷歌在 2018 年时提出的一种基于 Transformer 的双向编码器的表示学习模型&#xff0c;它在多个 NLP 任务上刷新了记录。它利用了大量的无标注文本进行预训练&#xff0c;预训练任务有掩码语言模型和下一句预测&#xff0c;掩码语言模型指的是随机地替换文本中…

项目管理流程

优质博文 IT-BLOG-CN 一、简介 项目是为提供某项独特产品【独特指:创造出与以往不同或者多个方面与以往有所区别产品或服务&#xff0c;所以日复一日重复的工作就不属于项目】、服务或成果所做的临时性【临时性指:项目有明确的开始时间和明确的结束时间&#xff0c;不会无限期…

线框图是什么?怎么画?看这篇文章就够了

产品设计中&#xff0c;简洁清晰传达出复杂概念是件难度不小的事&#xff0c;但也是很重要的事&#xff0c;这不仅关系设计的准确性&#xff0c;更关乎整个项目的顺利进行。在这种情境下&#xff0c;线框图的作用不容小觑。它作为设计思路的初步可视化手段&#xff0c;不仅是产…

GIS项目实战06:超详细Node.js安装及系统环境配置

简单的说 Node.js 就是运行在服务端的 JavaScript。 Node.js 是一个基于 Chrome JavaScript 运行时建立的一个平台。 Node.js 是一个事件驱动 I/O 服务端 JavaScript 环境&#xff0c;基于 Google 的 V8 引擎&#xff0c;V8 引擎执行 Javascript 的速度非常快&#xff0c;性能…

HCIA——20应用层:C/S、P2P、peer

学习目标&#xff1a; 计算机网络 1.掌握计算机网络的基本概念、基本原理和基本方法。 2.掌握计算机网络的体系结构和典型网络协议&#xff0c;了解典型网络设备的组成和特点&#xff0c;理解典型网络设备的工作原理。 3.能够运用计算机网络的基本概念、基本原理和基本方法进行…

LabVIEW扫描探针显微镜系统开发

在纳米技术对高精度材料特性测量的需求日益增长。介绍了基于LabVIEW开发的扫描探针显微镜&#xff08;SPM&#xff09;系统。该系统不仅可以高效地测量材料的热物性&#xff0c;还能在纳米尺度上探究热电性质&#xff0c;为材料研究提供了强大的工具。 系统基于扫描探针显微技…

uniapp h5 生成 ubuntu桌面程序 并运行方法

uniapp h5 生成 ubuntu桌面程序 并运行方法,在window环境下开发&#xff0c;发布到ubuntu桌面&#xff0c;并运行 1、安装Nodejs 安装包官方下载地址&#xff1a;https://www.nodejs.com.cn/ 安装完后cmd&#xff0c;如图&#xff0c;即安装成功 2、通过Nodejs安装 electron…

基于大整形的运算收录

目录 目录 目录 前言 为什么要大整数 大整形的加/减法 大整形的乘法 大整形除法 大整形开方 代码实现 前言 好久没有更新博客了&#xff0c;hhh。时隔三个月&#xff0c;我又回来了。先来点简单的大整形&#xff0c;虽说简单&#xff0c;但是在编写的时候还是debug了…

redis优化系列(六)

本期分享redis内存过期策略&#xff1a;过期key的处理 Redis之所以性能强&#xff0c;最主要的原因就是基于内存存储。然而单节点的Redis其内存大小不宜过大&#xff0c;会影响持久化或主从同步性能。 可以通过修改配置文件来设置Redis的最大内存&#xff1a; maxmemory 1gb …

远程登录Linux服务器:命令+工具版

通常在工作过程中&#xff0c;公司中使用的真实服务器或者是云服务器&#xff0c;都不允许除运维人员之外的员工直接接触&#xff0c;因此就需要通过远程登录的方式来操作。 所以&#xff0c;远程登录工具就是必不可缺的&#xff0c;目前&#xff0c;比较主流的有 Xshell,SSHS…

京东云开发者DDD妙文欣赏(2)报菜名和化繁为简的创新

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 京东云开发者原文链接&#xff1a;DDD落地实践-架构师眼中的餐厅>>&#xff0c;以下简称《餐厅》。 我截图时&#xff0c;阅读量有6044&#xff0c;在同类文章中已经算是热文了…