数据结构(1)——算法时间复杂度与空间复杂度

目录

前言

一、算法

1.1算法是什么?

1.2算法的特性

1.有穷性

2.确定性

3.可行性

4.输入

5.输出

二、算法效率

2.1衡量算法效率

1、事后统计方法

2、事前分析估计方法

2.2算法的复杂度

2.3时间复杂度

2.3.1定义

2.3.2大O渐进表示法

2.3.3常见时间复杂度举例

1、O(N)

2、O(N+M)

3.O(1)

4、O(N²)

5、O(logN)

6、O(N)递归

7、O(N²)斐波那契

2.4空间复杂度

2.4.1定义

2.4.2空间复杂度举例

1、O(1)

2、O(N)

2.5常见的函数增长率

总结


前言

“数据结构”是计算机程序设计的重要理论技术基础,它不仅是计算机的核心课程,而且已成为其它理工专业的热门选修课。                                                     ——《数据结构C语言版》严蔚敏


一、算法

1.1算法是什么?

首先,我们总能听见算法算法的,到最后一问你算法是什么?你支支吾吾的回答说不就是一些计算的方式吗?难不成还有其它解释方法。对此,在严蔚敏的书中是这么解释的:

算法(algorithm)是对特定问题求解步骤的一种描述,它是指令的有限序列,其中每一条指令表示一个或者多个操作

我们生活中的问题都需要一定步骤的解决,算法亦如此,你解决一个问题,需要有先后的顺序和方法,最后才能解决好,经过这些操作和步骤,整合起来才是这特定问题的算法。

1.2算法的特性

当然解决问题的算法也是有一些特性的,在这里说明出来:

1.有穷性

一个算法必须是又穷的,要不然在解决什么问题,我们要的是通过算法来获取最后的结果,实现最后的结果,而不是无穷下去,最后什么都得不到。当然是对一些合法的输入值,每一步都可以在有穷的时间内完成,最后也在有穷步之后结束。

2.确定性

算法中每一条操作和指令必须要有明确的含义,这样才能确定要做什么,要干什么,在任何条件下,算法只有唯一的一条执行路径,即对于相同的输入只能得出相同的输出。你得到最后这个结果后,你不能再来一次后不得这个结果了,那么肯定就是出问题了。

3.可行性

这个算法必须是可行的,因为你不可行那你在算什么,算法中的实现都是可以通过已经实现的基本运算执行有限的次数下实现的。

4.输入

一个算法有零个或者多个的输入,这些输入取自某个特定的对象的集合。像有一些不用输入就只需要进行操作的命令。

5.输出

一个算法有一个或者多个的输出,这些输出是同输入有着某些特定的关系的量。

而且通常一个算法的好坏,看看有没有下面的五条:

1、正确性

2、可读性

3、健壮性

4、效率与低存储量需求

如果你的算法满足了这些,那么它就是一个“好”的算法。

二、算法效率

2.1衡量算法效率

一般衡量算法效率有两种方法:

1、事后统计方法

因为很多计算机内部都有计时器的功能,有些可能会精细到毫秒级别,不同的算法的程序可以通过一组或者成千上万组的数据来区分这个算法的优势和劣势,但有这种方式有一个缺陷,就是每一次衡量都需要先运行依据算法编制的程序,并且所得的时间的统计量还依赖于计算机硬件,软件环境等因素,所以有时候会掩盖算法本身的优势和劣势。

2、事前分析估计方法

一个高级程序语言编写的程序在计算机上消耗的时间取决于算法选用的策略、问题的规模、书写程序的语言(因为语言级别越高,执行效率就越低)、编译程序所产生的机器代码的质量、机器执行指令的速度。基于这些要求,我们可以用一个问题规模的函数来分析估计。

2.2算法的复杂度

我们之前提到了算法满足五条就是一个“”的算法,但其中的第四条提到了“效率与低存储需求”,这里判断的方法就涉及到了时间与空间两个方面,也就是看时间复杂度和空间复杂度。

时间复杂度主要衡量的是一个算法的运行速度的快慢,而空间复杂度主要是衡量一个算法运行所需要的额外空间。

2.3时间复杂度

2.3.1定义

在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间,一个算法执行所耗费的时间,从理论上来说,是不能算出来的,但一个算法所花费的时间与其中的语句的执行次数成正比例,算法中的基本操作的执行次数,为算法的时间复杂度。

例如下面的代码:

for (int i = 0; i < N; i++)
{for (int j = 0; j < N; j++){sum=i+j}
}

我们只需要计算基本语句和问题规模N的数学表达式就可以。

这里是两次循环,每一个循环都是N次循环,所以F(N)=N²。而在这里我们用大O表示法来表示时间复杂度,也就是O(N²)。

2.3.2大O渐进表示法

实际我们在计算机时间复杂度的时候,并不需要一定要计算精准准确的执行次数,而只需要大概执行次数就可以。

大O符号:用于描述函数渐进行为的数字符号

推导大O阶的方法:

1、用常数1取代运行时间中的所有加法常数

2、在修改后的运行次数函数中,只保留最高阶项。

3、如果高阶项存在且不是1,则去除与这个项目相乘的常数,得不到的结果就是大O阶。

有些算法的时间复杂度会存在最好、平均和最坏的情况:

最坏情况:任意输入规模的最大运行次数(上界)

平均情况:任意输入规模的期望所运行次数

最好情况:任意输入规模的最小运行次数(下界)

例如我们如果在一组数中找一个数:

1 2 3 4 5 6 7 8 9....N

如果找1的话就是最好的情况一次就找到了,最坏的情况就是N次找到,平均就是N/2次找到。

在实际中一般情况关注的是算法最坏的情况,所以它的时间复杂度就是O(N)。

2.3.3常见时间复杂度举例

1、O(N)

void Func1(int N)
{int cout = 0;for (int n = 0; n < 2 * N; n++){++cout;}int cout1 = 5;while (cout1--){++cout;}printf("%d \n", cout);
}

这里我们可以进行推导,来计算基本语句和问题规模N的函数等于什么?这里经历了一个循环N次,接下来又是一个常数的循环,最后也就是F(N)=N+5。

因为时间复杂度里面有常数要舍去,所以最后用大O表示也就是O(N)。

2、O(N+M)

void Func2(int N, int M)
{int cout = 0;for (int i = 0; i < N; i++){cout++;}for (int i = 0; i < M; i++){cout++;}printf("%d \n", cout);
}

这里同样的,计算基本语句和问题规模N,M的数学表达式:

第一个循环循环了N次,第二个循环了M次,所以最后是F(N,M)=N+M,时间复杂度也就是O(N+M)。

3.O(1)

void Func3(int N)
{int cout = 0;for (int i = 0; i < 10000; i++){cout++;}printf("%d \n", cout);
}

这里也就是找N和基本语句的表达式,我们发现这里就一个循环了10000次,是一个常数,用大O表示就是O(1)。

4、O(N²)

void BubbleSort(int* a, int n)
{assert(a);for (size_t end = n; end > 0; --end){int exchange = 0;for (size_t i = 1; i < end; ++i){if (a[i - 1] > a[i]){Swap(&a[i - 1], &a[i]);exchange = 1;}}if (exchange == 0)break;}
}

这里是一个简单的冒泡排序,Swap是用来交换数字的,这里计算一下问题规模n的函数表达式;

这是一个嵌套循环,外面一层循环走了n次,里面的从1开始循环,如果前一个大于当前的数字就交换,这里可以发现得需要除以2,所以最好的情况下就是一趟循环就找到了,也就是O(N),最坏就是两层,也就是F(N)=N*(N+1)/2,也就是O(N²)。

5、O(logN)

int BinarySearch(int* a, int n, int x)
{assert(a);int begin = 0;int end = n - 1;while (begin < end){int mid = begin + ((end - begin) >> 1);if (a[mid] < x)begin = mid + 1;else if (a[mid] > x)end = mid;elsereturn mid;}return -1;
}

这是一个经典的用二分查找x的值,这里就是找出问题规模n的表达式。我们知道二分查找是折半的,每一次都是平方倍的,所以n=N²,则F(N)=logN,(以二为敌N的对数),最好情况就是O(1),最坏就是O(logN)。

6、O(N)递归

long long Fac4(size_t N)
{if (0 == N)return 1;return Fac4(N - 1) * N;
}

这里给出了一个递归计算阶乘,找问题规模N的表达式,这里我们反着推也就是N*(N-1)*(N-2)...*1,我们发现中间经历的N次,所以F(N)=N;所以用大O表示就是O(N)。

7、O(2ⁿ)斐波那契

long long Fib(size_t N)
{if (N <= 1) {return N;}return Fib(N-1) + Fib(N-2);
}

这里就是一个斐波那契数列,这里也是通过递归进行两次两次的实现,所以最后也就是表示N需要2ⁿ次,也就是用大O表示法就是O(2ⁿ)。

2.4空间复杂度

2.4.1定义

空间复杂度也是一个数学表达式,是对一个算法在运行过程中临时占用内存空间大小的衡量。

空间复杂度不是程序占用了多少字节的空间,而是算的是变量的个数,计算规则基本和时间复杂度类似,也是用大O渐进表示法。

函数运行时所需要的栈空间(存储参数,局部变量,一些寄存器信息等)在编译期间已经确定好了,因此空间复杂度主要通过函数在运行的时候显示申请的额外空间来确定。

这里说一下:根据经验大多数空间复杂度都是O(1)或者O(N)。

2.4.2空间复杂度举例

1、O(1)

void BubbleSort(int* a, int n)
{assert(a);for (size_t end = n; end > 0; --end){int exchange = 0;for (size_t i = 1; i < end; ++i){if (a[i - 1] > a[i]){Swap(&a[i - 1], &a[i]);exchange = 1;}}if (exchange == 0)break;}
}

依旧是冒泡函数,这里使用了常数个变量空间,所以最后空间复杂度就是O(1)。

2、O(N)

long long Fac(size_t N)
{if(N == 0)return 1;return Fac(N-1)*N;
}

这里是那个阶乘的递归,我们知道递归调用的时候是调用自身,并且也是占用栈帧的,所以这里就是调用了N次,也就是开辟了N个栈帧,而每一个栈帧用了常数个变量,所以这里的空间复杂度就是O(N)。

2.5常见的函数增长率

这里给出常见的函数增长率:


总结

今天主要对算法,算法的时间、空间复杂度进行了分析和学习,这里会计算会看就可以。

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

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

相关文章

网络HTTP详细讲解

学习目标 什么是HTTPHTTP的请求和响应常见的HTTP状态码HTTP的安全性 什么是HTTP&#xff1f;HTTP的请求和响应&#xff0c;常见的HTTP状态码&#xff0c;HTTP的安全性 什么是HTTP HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;是一种用…

Oracle 的归档日志文件(Archive log files)

-- 4.Oracle 的归档日志文件(Archive log files) /************************************************************************************************************************************************************* -- 1. RMAN 备份,开启archivelog后,log过多过大造成造…

spring aop失效场景

aop基于代理&#xff08;jdk动态代理 / cglib代理&#xff09;实现&#xff0c;即new了新的类实例&#xff0c;代理了原来的定义的类实例。 目录 1. final修饰的方法无法被代理2. 静态方法无法被代理3. 内部方法调用&#xff0c;即this.method()无法被代理4. 私有方法不能代理5…

Page Assist - 本地Deepseek模型 Web UI 的安装和使用

Page Assist Page Assist是一个开源的Chrome扩展程序&#xff0c;为本地AI模型提供一个直观的交互界面。通过它可以在任何网页上打开侧边栏或Web UI&#xff0c;与自己的AI模型进行对话&#xff0c;获取智能辅助。这种设计不仅方便了用户随时调用AI的能力&#xff0c;还保护了…

GRN前沿:STGRNS:一种基于transformer的可解释方法,用于从单细胞转录组数据推断基因调控网络

1.论文原名&#xff1a;STGRNS: an interpretable transformer-based method for inferring gene regulatory networks from single-cell transcriptomic data 2.发表日期&#xff1a;2023.4.2 摘要&#xff1a; 动机&#xff1a;单细胞RNA测序&#xff08;scRNA-seq&#xf…

vite共享配置之---css相关

vite和webpack都有对样式的处理&#xff0c;涉及到的有css、sass、scss、postcss、模块化&#xff0c;以下是vite和webpack对样式的处理方式 特性ViteWebpackCSS 处理方式自动处理&#xff0c;无需配置&#xff0c;使用浏览器的原生支持需要配置 style-loader 和 css-loader&a…

OpenAI 实战进阶教程 - 第四节: 结合 Web 服务:构建 Flask API 网关

目标 学习将 OpenAI 接入 Web 应用&#xff0c;构建交互式 API 网关理解 Flask 框架的基本用法实现 GPT 模型的 API 集成并返回结果 内容与实操 一、环境准备 安装必要依赖&#xff1a; 打开终端或命令行&#xff0c;执行以下命令安装 Flask 和 OpenAI SDK&#xff1a; pip i…

深入浅出:旋转变位编码(RoPE)在现代大语言模型中的应用

在现代大语言模型&#xff08;LLMs&#xff09;中&#xff0c;位置编码是一个至关重要的组件。无论是 Meta 的 LLaMA 还是 Google 的 PaLM&#xff0c;这些模型都依赖于位置编码来捕捉序列中元素的顺序信息。而旋转变位编码&#xff08;RoPE&#xff09; 作为一种创新的位置编码…

MATLAB中matches函数用法

目录 语法 说明 示例 匹配文本 使用模式匹配十六进制数 匹配多个字符串 忽略大小写 matches函数的功能是确定模式是否与字符串匹配。 语法 TF matches(str,pat) TF matches(str,pat,IgnoreCasetrue) 说明 TF matches(str,pat) 会在指定模式与 str 有匹配时返回 1…

【信息系统项目管理师】第20章:高级项目管理 详解

更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 20.1 项目集管理20.2 项目组合管理20.3 组织级项目管理20.4 量化项目管理20.5 项目管理实践模型本章是将第三版的第20章、第21章、第18章、第25章、第2章的PRINCE2进行了合并,包括项目集管理、项目组合管理、组…

个人笔记---关于详解threadlocal 上下文环境存储的最佳数据类型

个人原因很久没有写代码,对于一些基础的数据类型有一些忘记,可以根据gpt和我当时的问答进行复习 关于拦截器,由于在请求的到达controller处理器之前,拦截器(当然过滤器也可以实现,我感觉都差不多)就把上下文设置在了线程副本中,那么这个请求到处理器的这些代码进行查询出来的上…

vue3 的 onScopeDispose 是什么作用

onScopeDispose 是 Vue 3 中用于管理响应式副作用的一个重要 API&#xff0c;主要用于在当前活跃的 effect 作用域上注册一个处理回调函数。当这个作用域停止时&#xff0c;所注册的回调函数会被调用。这种机制使得开发者能够有效地清理和管理资源&#xff0c;尤其是在组合式函…

DeepSeek 部署过程中的问题

文章目录 DeepSeek 部署过程中的问题一、部署扩展&#xff1a;docker 部署 DS1.1 部署1.2 可视化 二、问题三、GPU 设置3.1 ollama GPU 的支持情况3.2 更新 GPU 驱动3.3 安装 cuda3.4 下载 cuDNN3.5 配置环境变量 四、测试 DeepSeek 部署过程中的问题 Windows 中 利用 ollama 来…

医疗信息分析与知识图谱系统设计方案

医疗信息分析与知识图谱系统设计方案 0. 系统需求 0.1 项目背景 本系统旨在通过整合医疗机构现有的信息系统数据&#xff0c;结合向量数据库、图数据库和开源AI模型&#xff0c;实现医疗数据的深度分析、疾病预测和医疗知识图谱构建&#xff0c;为医疗决策提供智能化支持。 …

QImage与AVFrame互转

未验证&#xff0c;仅供参考&#xff0c;此方法感觉不是很好 先是AVFrame转QImage #pragma execution_character_set("utf-8")static int decode_write_frame(AVCodecContext *avctx, AVFrame *frame, int *frame_count, AVPacket *pkt, int last) {int len, got_f…

基础算法——二维前缀和

二维前缀和 我们先前已经了解了前缀和思想&#xff0c;二维前缀和感觉上就是一维前缀和的进阶&#xff0c;下面 &#xff0c;我们剖析一下两种前缀和。 一维前缀和 一维前缀和的核心就是这两个公式&#xff0c;二维前缀和也差不多的嘞 下面我们来推理一下二维前缀和 已知&a…

PySPARK带多组参数和标签的SparkSQL批量数据导出到S3的程序

设计一个基于多个带标签SparkSQL模板作为配置文件和多组参数的PySPARK代码程序&#xff0c;实现根据不同的输入参数自动批量地将数据导出为Parquet、CSV和Excel文件到S3上&#xff0c;标签和多个参数&#xff08;以“_”分割&#xff09;为组成导出数据文件名&#xff0c;文件已…

如何安装LangChain软件包

前言 LangChain是一个强大的框架&#xff0c;用于构建使用大型语言模型&#xff08;LLMs&#xff09;的应用程序。它提供了一系列软件包和工具&#xff0c;帮助开发人员将LLMs集成到他们的工作流程中。然而&#xff0c;由于其模块化设计&#xff0c;LangChain生态系统可能会让…

每日Attention学习19——Convolutional Multi-Focal Attention

每日Attention学习19——Convolutional Multi-Focal Attention 模块出处 [ICLR 25 Submission] [link] UltraLightUNet: Rethinking U-shaped Network with Multi-kernel Lightweight Convolutions for Medical Image Segmentation 模块名称 Convolutional Multi-Focal Atte…

2. K8S集群架构及主机准备

本次集群部署主机分布K8S集群主机配置主机静态IP设置主机名解析ipvs管理工具安装及模块加载主机系统升级主机间免密登录配置主机基础配置完后最好做个快照备份 2台负载均衡器 Haproxy高可用keepalived3台k8s master节点5台工作节点(至少2及以上)本次集群部署主机分布 K8S集群主…