数据结构与算法笔记(一)---时间复杂度与空间复杂度

前言

以自述式的笔记展示,尽可能用最好理解的方式去叙述我对知识点的理解,方便有需求的小伙伴查看理解,同时锻炼自身的表达能力,共同学习,共同进步,争取“双赢”!

注:本文章根据自身学习的笔记和自身理解编写,难免存在纰漏或不足之处,如有不足,恳请各位在评论区批评指正,谢谢!

在编写和分析算法过程中我们如何去评价一个算法的好坏程度呢?这时候,我们有时会听到“诶!我昨天晚上对那个O(N)算法进行优化,写出了一个O(logN)的算法。”等等,其中这段话中的O(N)和O(logN)便是描述算法好坏程度的一种方式-----时间复杂度空间复杂度,而这个表示法我们通常称作“大O的渐进表示法”。接下来,我来为大家分别讲述一下时间复杂度和空间复杂度的概念、作用以及计算方式。

一、时间复杂度

1、基本概念

       用于衡量算法的执行时间长短的量度

2、作用

       1)事先大致估计算法的运行时间;

       2)便于评价算法的好坏,且提供了一个衡量方式

3、计算规则

       所谓时间复杂度,即用于计算算法运行时间的量。在实际情况下,要准确去计算一个算法的运行时间是比较麻烦的,因为一串代码的运行在不同的机器上或环境中的运行时间可能大同小异,也就是说。同一个算法的运行时间还受到软硬件等一系列的影响,但是人们为了能够描述一个算法的优劣程度,便想出这样的办法-----通过观察算法中的每行代码的执行次数进行判断。

       比如以下代码的时间复杂度的判断:

double f( int n, double a[], double x ) {
	int i;
	double m = 1.0;
	double Sum = 0;
	for (i = 0; i < n; i++) {
		if (i == 0) {
			Sum = a[0];
		} else {
			m *= x;
			Sum += a[i] * m;
		}
	}
	return Sum;
}

       我们观察这段代码,会发现需要执行的最多次数是1+1+1+2n+1=2n+4次,为什么呢,因为函数中前三行代码分别执行了1次,然后一个for循环执行了n~2n次,这里我们要了解一个点:就是在我们计算算法的时间复杂度的时候,一般使用的最坏情况计算,因为这样更能凸显一个算法的好坏,为什么怎么说呢?咱想想,如果用最坏的情况去考虑其时间复杂度,那么我们就会努力想这个标准减少时间,那么就算实际情况下执行了这个时间,我们的算法优化的也不错了,更何况这只是一个最坏的情况呢,换句话说,使用最坏的情况去描述一个算法的时间复杂度更加靠谱。接着return语句执行一次,一共就2n+4次了,因此这个代码的时间复杂度我们就表示成O(2n+4),意味着该穿代码时间复杂度为O(2n+4),且我们把这种表示方法称为大O的渐进表示法

       但是呢,在实际开发过程中,我们编写的算法或者程序并没有这么简单,往往代码量是特别大的,其中的方方面面混杂了不同的语句,且由于一些循环语句可能混杂了很多字母表示的执行次数(如n^2、logN等等),通常不一定只含可数的次数,就可能导致我们人为就散起来比较麻烦。因此,我们在计算时间复杂度的时候,通常只取执行次数中次数最高的去除常系数的值作为时间复杂度的量,我们把这种评价算法执行时间长短的方式叫做算法渐进时间复杂度。比如执行n^2+3n+5次,那么我们只取n^2,所以最终的时间复杂度为O(n^2);执行6n+7次,那么我们只取n,因此时间复杂度为O(n);特殊的是:执行的是常数次,那么就取1,即最终的时间复杂度为O(1)......

       那么,为什么要这样去计算呢,有什么道理?这里我说一说原因:因为当出现次数高且不能直接判断准确次数的情况(即用n或者其他字母表示的次数)时,如果n足够,那么那些低次数、为常数的值对总的执行次数的影响就显得很弱了,因此我们计算时间复杂度时只需要关注那些次数高的部分,且不用包含常系数。如果难以理解,也可以类比数学中的极限的思想,如n^2+n+5,如果n等于10或100或10^5的话,那么总的次数为10^10+10^5+5,而10^5+5相对10^10来说就显得微乎其微了,完全可以忽略不计,这样理解。因此我们计算时间复杂度时只取次数最大的部分,就是这个原因。

       因此,总的来说,渐进时间复杂度的计算技巧在于:

         1、找出算法中执行次数最多的位置。

         2、然后分析其执行次数。

         3、接着用大O表示法表示出来即可。

        我们想想,我们平时编写代码时,那些地方会出现反复执行的地方呢?一般来说这种地方存在于循环语句中,即for循环或while循环中,值得注意的是,除了循环你控制语句可能出现执行次数多的情况之外,还有一个地方也经常出现,即递归,(最典型的例子阶乘或斐波那契的相关算法)。因此,我们可以在进行第一步操作时多关注这两方面

       另外,我们计算时间复杂度时,一定要具体问题具体分析,因为某些情况下,其时间复杂度会受到代码逻辑的干扰而出现多种可能的情况,这个时候我们如何确定代码执行次数呢?

       就比如说,一个算法中有两个for循环,且循环次数分别为M,N,我们知道,确定执行次数时主要观察的部分之一就是循环语句,因此初步判断执行次数为M+N。但是,这个时候我们有必要留意一下,因为如果M和N的最坏情况的值的关系对实际估计是有影响的:比如,若M>>N,则此时N就可以忽略不计了,那么此时的时间复杂度就是O(M);若M接近N,则M+N可近似看作2M或2N,然后去除常系数,因此此时时间复杂度为O(M)或者O(N)。常出现这这种情况的地方在于:代码中循环语句与存在条件判断语句(if-else语句、switch语句等)相关联的时候具体例子关注后续题型解析或自己下面练习体会。

       几种常见的时间数量积的时间复杂度表示:

   O(1)、O(n)、O(n^2)、O(nlogn)、O(2^n)、O(n!)

       由图我们很容易看出,常数级O(1)的执行次数是最少得,也是最优原地算法,其次是O(n),最慢的是O(n!)。因此,我们在设计算法时,尽量让时间复杂度落在前几种情况最合适。

       这是时间复杂度好坏排序:O(1)<O(n)<O(n^2)<O(nlogn)<O(2^n)<O(n!)

4、注意事项

        在进行时间复杂度的判断时,有这么几个注意事项。

  1、时间复杂度的表示

        1)现在普遍使用的表示方法是大O表示法,即O(估计执行次数)。

        2)执行次数的表示:对于对数的情形,因实际情况中一般式以2为底的对数,由于对数的表示时底数偏下不好表示,因此我们通常写成logN的形式表示对数级时间,即O(logN)。也可能有人表示成lgN,但不推荐,因为lg可能是以10为底,容易产生二义性。

  2、执行次数值的选取

        1)取代码中执行次数最多的代码块做分析即可,通常是循环控制语句递归语句中。

        2)选取的值是次数最高的,且要去除其常系数。

        3)若本身是常数,则取1,相当于时间不变。

        4)执行次数受代码逻辑影响(常见于循环语句与条件语句关联时)的情况,具体情况具体分析。

二、空间复杂度

1、基本概念、作用以及计算规则

        空间复杂度,即用于描述一个算法占用空间的大小的一种方式。

        讲完时间复杂度以后,空间复杂度就相对比较轻松了,因为空间复杂度的表示和时间复杂度几乎相同,也是用的大O的渐进表示法。只是空间复杂度表示的是一个算法在运行时所占用的临时内存,我们不会用byte去描述它的空间大小,因为单位太小,没什么太大的意义。所以空间复杂度的计算方式是去看代码中变量的个数,且其计算规则与时间复杂度的计算规则类似,我这里就不再赘述。

2、注意事项

1、空间不累计:

       在循环语句中,若某个变量再循环语句中定义,那么该变量会被反复定义,可能有人会问:那这每一次定义是不是都算一个新的变量呢?答案是否定的,再循环中定义的变量总是使用的同一块空间,并不会重新开辟空间。

2、地址的开辟会利用空间一次,相当于定义了一个新变量

       当涉及到地址的变量如动态内存的开辟(malloc)递归的调用(建立栈帧)等,都会多开辟空间,因此每发生一次都相当于空间复杂度为O(1),都需要算进去。

三、总结

  1、本次讲述了数据结构与算法中最基础也必不可少的概念-----时间复杂度和空间复杂度

  2、时间复杂度----描述算法的执行速度,用执行次数最大的部分表示。

  3、空间复杂度----描述算法占用空间的大小,用变量定义个数表示。

  4、空间复杂度和时间复杂度一般用用大O的渐进表示法描述。

如有不足,请在评论区留言。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java面试八股之WeakHashMap的工作原理

简述WeakHashMap的工作原理 弱键&#xff08;Weak Keys&#xff09;&#xff1a; WeakHashMap 的键&#xff08;keys&#xff09;是通过 WeakReference 弱引用进行封装的。弱引用是一种特殊的引用类型&#xff0c;它不会阻止所引用的对象被垃圾收集器回收。这意味着&#xff…

机器人操作系统ROS2学习—控制小海龟运动

将Ubuntu系统和ROS2安装完成后&#xff0c;就可以进行调用小海龟运动了。 一、打开Ubuntu系统后&#xff0c;调用终端窗口。有3 种方法可以打开启动终端: 1、通过快捷键CtrAItT; 2、桌面左下角有个显示应用的菜单&#xff0c;点击后找到终端“Terminal”图标&#xff0c;打…

kubernetes二进制多master部署

文章目录 一、master02 节点部署&#xff08;在上期博客部署完成的情况下&#xff09;1、准备master02节点需要的文件2、修改配置文件kube-apiserver中的IP3、启动各服务并设置开机自启4、查看node节点状态 二、负载均衡部署1、配置load balancer集群双机热备负载均衡1.1 准备n…

英飞凌SiC模块为小米电动车提供动力

至2027年之际&#xff0c;SiC功率模块与裸片产品将荣耀登场&#xff0c;助力小米电动汽车新品SU7璀璨问世。英飞凌&#xff0c;这家业界翘楚&#xff0c;将倾其所能&#xff0c;为小米SU7 Max提供两颗HybridPACK Drive G2 CoolSiC 1200 V模块&#xff0c;如同给电动汽车的心脏注…

万字长文破解 AI 图片生成算法-Stable diffusion (第一篇)

想象一下&#xff1a;你闭上眼睛&#xff0c;脑海中构思一个场景&#xff0c;用简短的语言描述出来&#xff0c;然后“啪”的一声&#xff0c;一张栩栩如生的图片就出现在你眼前。这不再是科幻小说里才有的情节&#xff0c;而是Stable Diffusion——一种前沿的AI图片生成算法—…

OpenHarmony 实战开发——ArkUI容器类API介绍

容器类&#xff0c;顾名思义就是存储的类&#xff0c;用于存储各种数据类型的元素&#xff0c;并具备一系列处理数据元素的方法。在 ArkUI 开发框架中&#xff0c;容器类采用了类似静态的语言来实现&#xff0c;并通过 NAPI 框架对外提供。通过对存储位置以及属性的限制&#x…

Signal 即将成为JavaScript的一部分

什么是响应性&#xff1f; 在过去的几年中&#xff0c;响应性成为了所有现代前端框架以及React库的核心。 对于不熟悉前端开发的人来说&#xff0c;起初这可能是一个令人困惑的概念&#xff0c;因为它改变了常规的、自上而下的、从调用者到被调用者的顺序工作流。 在响应性范…

OpenAI春季发布会速览,盘点近30天AI大事件

OpenAI发布会速览 北京时间5月14日凌晨1点&#xff0c;OpenAI在官网举行了"春季更新"活动&#xff0c;推出了全新的旗舰模型“GPT-4o”&#xff0c; 这款模型具备处理文本、图片、视频、语音的全能处理能力&#xff0c;能实时响应用户需求&#xff0c;并进行语音回应…

Altium Designer封装库和元器件符号库下载与导入教程(SnapEDA 、Ultra Librarian、Alldatasheetcn)

1.AD封装库和元器件符号库下载网址 以下是一些全球热门的Altium Designer封装库和元器件符号库下载网址推荐&#xff1a; Altium Content Vault (现称为Altium Manufacturer Part Search)&#xff1a;这是Altium官方提供的元器件库&#xff0c;可以直接在Altium Designer中使用…

腾讯开源混元DiT文生图模型,消费级单卡可推理

节前&#xff0c;我们组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、今年参加社招和校招面试的同学。 针对大模型技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备面试攻略、面试常考点等热门话题进行了深入的讨论。 总结链接…

层次式体系结构概述

1.软件体系结构 软件体系结构可定义为&#xff1a;软件体系结构为软件系统提供了结构、行为和属性的高级抽象&#xff0c;由构成系统的元素描述、这些元素的相互作用、指导元素集成的模式以及这些模式的约束组成。软件体系结构不仅指定了系统的组织结构和拓扑结构&#xff0c;并…

速度与激情:Redis如何以核心数据结构驱动极致性能

关注微信公众号 “程序员小胖” 每日技术干货&#xff0c;第一时间送达&#xff01; 引言 Redis是一个开源的内存数据结构存储系统&#xff0c;它支持多种类型的数据结构&#xff0c;如字符串、散列、列表、集合、有序集合等。Redis以其出色的性能和低延迟特性而闻名&#xf…

最小质数对-第12届蓝桥杯国赛Python真题解析

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第63讲。 最小质数对&#…

【软考】模拟考卷错题本2024-05-14

1 活动图-计算时间差 审题&#xff0c;第几天~选的3、10是结束了上一次的活动并未开始呢 &#xff01;所以记得按照正常的语序表达哦&#xff01; 2 队列-算长度 代入法&#xff0c;设计一个开始为0&#xff0c;结尾为9 &#xff0c;容量为10即M的队列&#xff1b;带入计算当前…

【车载开发系列】AutoSar中的Port

【车载开发系列】AutoSar中的Port 一. Port概念 AutoSAR 接口定义了 SWC 之间、BSW 模块之间以及 SWC 和 BSW 模块之间交互的信息。AutoSAR 接口通过 SWC 和/或 BSW 模块端口&#xff08;Port&#xff09;的形式实现。通过这些端口&#xff0c;SWC 和 BSW 模块之间实现了数据…

MYSQL SQL3

1.DCL:Global level 所有库&#xff0c;所有表的权限 Database level:某个数据库中所有表的权限 Table level: 库中某个表的权限 Column level:表中的某个字段的权限 管理:创建用户create user 用户名localhost(ip地址&#xff0c;“%”除了本机登录其他的都可以登录…

iOS ------ 多线程基础

一&#xff0c;进程和线程 1&#xff0c;进程 定义&#xff1a; 进程是指在系统中正在运行的一个应用程序每个进程之间是独立的&#xff0c;每个进程均运行在其专有的且受保护的内存进程是系统进行资源分配和调度的一个独立单位 补充&#xff1a;iOS系统是相对封闭的系统&a…

(C语言)队列实现与用队列实现栈

目录 1.队列 1.1队列的概念及结构 1.2 队列的实际应用联想 1.3队列的实现 2. 队列应用——队列实现栈 主要思路 1.队列 1.1队列的概念及结构 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进…

内网渗透瑞士军刀-impacket工具解析(二)

impacket工具解析之Kerberos认证协议 上一期我们介绍了impacket中ntlm协议的实现&#xff0c;在Windows认证中除了使用ntlm认证&#xff0c;还支持Kerberos认证协议&#xff0c;Kerberos认证也是Windows 活动目录中占比最高的认证方式。 什么是Kerberos协议&#xff1f; Kerb…

什么?你设计接口什么都不考虑?

如果让你设计一个接口&#xff0c;你会考虑哪些问题&#xff1f; 1.接口参数校验 接口的入参和返回值都需要进行校验。 入参是否不能为空&#xff0c;入参的长度限制是多少&#xff0c;入参的格式限制&#xff0c;如邮箱格式限制 返回值是否为空&#xff0c;如果为空的时候是…