数据结构第2问:什么是算法?

算法

算法是一组用于解决具体问题的、明确的、有序的步骤或规则,能够在有限的时间内通过这些步骤得到问题的答案。

算法的5个重要特性:

  1. 有穷性:算法必须在有限的步骤内结束,不能无限循环,保证最终能够得到结果。
  2. 确定性:算法的每一步操作都有明确的定义,没有歧义,保证执行结果唯一。
  3. 可行性:算法的每个步骤都必须是可行的,即能够在有限时间内通过基本操作完成。
  4. 输入:算法具有零个或多个输入,输入是算法运行所需要的数据。
  5. 输出:算法至少有一个或多个输出,输出是算法处理后的结果。

也就是说,一个基本的算法,必须能够在有限的步骤内将输入的数据通过具有确定含义的指令转换为所需要的输出结果。

以温度传感器原始数据的转化算法为例

  1. 有穷性:算法在有限步骤内完成原始数据的读取、处理和转化,确保不会无限循环,最终输出转换后的温度值。
  2. 确定性:相同的传感器原始数据通过算法处理后,每次都得到相同且明确的温度值,步骤明确无歧义。
  3. 可行性:算法使用的操作(如数据读取、数学计算等)都是实际可执行的,能够在传感器所在的硬件环境中完成。
  4. 输入:算法的输入是传感器采集到的原始数据(例如电压值或数字信号),这些数据用于后续转换计算。
  5. 输出:算法输出转换后的温度值(如摄氏度或华氏度),供系统显示或进一步处理使用。

设计一个好的算法还应该考虑什么?

算法的正确性:即能正确的解决问题。可读性:算法阅读起来清晰明了,便于理解。健壮性:算法对于非法数据能做出相应的处理,不会输出奇怪的数据。高效率与低存储需求:即算法既要执行的快而准,又要不占用过多存储空间。

还是拿温度传感器来讲:好的算法要能正常将温度值转化出来;写的代码要让人能看懂好理解;当测试环境温度超出温度传感器量程的时候要做相应处理,不能说单纯输出最大值或者最小值;温度转换过程花费的时间要少,占用的flash和ram都要少。(既要又要还要)

衡量一个算法的效率

通常衡量算法效率是通过时间复杂度空间复杂度来描述的。但是一个算法的优劣,不能仅仅依靠时间复杂度和空间复杂度来做出评判。在实际应用中,算法首先要能正确解决问题,然后在效率和内存占用这两者之间进行权衡。

时间复杂度

一个算法中所有语句在该算法中被重复执行的次数被定义为T(n),时间复杂度则是主要分析T(n)的数量级。因此,通常将算法中基本运算的执行次数的数量级作为该算法的时间复杂度。(即取T(n)中随n增长最快的项,将其系数置为1,作为时间复杂度的度量)。

  1. 最坏时间复杂度(Worst-case Time Complexity):指算法在所有可能的输入中,运行时间最长的情况所对应的时间复杂度。它保证了算法在任何输入下的最大耗时。
  2. 平均时间复杂度(Average-case Time Complexity):指算法在所有可能输入的概率分布下,运行时间的期望值。它反映了算法在一般情况下的性能表现,但计算比最坏情况复杂。
  3. 最好时间复杂度(Best-case Time Complexity):指算法在所有可能输入中,运行时间最短的情况所对应的时间复杂度。通常用于了解算法在理想条件下的表现,但不能代表算法的普遍效率。

常见的渐近时间复杂度(从小到大排列)为:

  • O(1) :常数时间复杂度,执行时间固定,不随输入规模变化。
  • O(log n) :对数时间复杂度,例如二分查找。
  • O(n) :线性时间复杂度,执行时间随着输入规模线性增长。
  • O(n log n) :线性对数时间复杂度,常见于高效排序算法如归并排序、快速排序。
  • O(n²) :平方时间复杂度,常见于简单的嵌套循环算法,如冒泡排序。
  • O(n³) :立方时间复杂度,常见于三重嵌套循环的算法。
  • O(2^n) :指数时间复杂度,常见于递归求解所有子集等问题。
  • O(n!) :阶乘时间复杂度,常见于全排列问题。

时间复杂度的计算

单层循环的时间复杂度计算

观察变量随次数的变化规律。

确定循环退出条件。

直接求循环的实际循环次数t。

举个例子
x = 2
while(x < n/2)x = 2 * x; 

假设运行t次程序退出循环,可得x的值随t的变化如下:

t1234
x481632

可以得到:
x=2t+1当:x=n/2时退出循环联立求解t的值得到:t=log2n+2找到增长最快的项为log2n,系数为1所以时间复杂度O(n)=log2n x = 2^{t+1}\\ 当: x = n/2 时退出循环\\ 联立求解t的值得到:t = log_2n+2\\ 找到增长最快的项为log_2n,系数为1 \\ 所以时间复杂度O(n) = log_2n x=2t+1当:x=n/2时退出循环联立求解t的值得到:t=log2n+2找到增长最快的项为log2n,系数为1所以时间复杂度O(n)=log2n

再举个例子
void func(int n)
{int i = 0;while(i*i*i <= n)i++;
}

假设运行t次程序退出循环,可得x的值随t的变化如下:

t1234
i1234

可以得到:
i=t当:i∗i∗i=n时退出循环联立求解t的值得到:t=n3找到增长最快的项为n3,系数为1所以时间复杂度O(n)=n3 i = t\\ 当: i * i * i = n 时退出循环\\ 联立求解t的值得到:t = \sqrt[3]{n}\\ 找到增长最快的项为\sqrt[3]{n},系数为1 \\ 所以时间复杂度O(n) = \sqrt[3]{n} i=t当:iii=n时退出循环联立求解t的值得到:t=3n找到增长最快的项为3n,系数为1所以时间复杂度O(n)=3n

两层循环的时间复杂度计算

  1. 首先确定外层循环的实际循环次数t作为内层循环次数求和的项数;

  2. 然后列出每个外层循环下内层的循环次数;

  3. 最后求和。

举个例子
int m = 0,i,j;
for(i = 1; i <= n; i++)for(j = 1; j <= 2*i; j++)m++;
计算m++语句的执行次数

先把内层看成O(1),那么外层循环次数为n,再看内层循环的 j 随运行次数变化:

t_n(项数)1234
j2468

即:
得到j与tn的关系为:j=2tn得到总次数为等差数列求和:总次数=(2+2tn)tn/2已知:内循环退出的临界点为j=2i,所以tn=i,所以总次数=(2+2i)i/2又已知:外循环退出的临界点为i=n;所以总次数=n(n+1)得到执行次数为:n(n+1) 得到j与t_n的关系为:j = 2t_n \\ 得到总次数为等差数列求和:总次数=(2 + 2t_n)t_n/2 \\ 已知:内循环退出的临界点为j = 2i,所以t_n=i,所以总次数=(2 + 2i)i/2 \\ 又已知:外循环退出的临界点为i = n;所以总次数=n(n + 1) \\ 得到执行次数为:n(n+1) 得到jtn的关系为:j=2tn得到总次数为等差数列求和:总次数=(2+2tn)tn/2已知:内循环退出的临界点为j=2i,所以tn=i,所以总次数=(2+2i)i/2又已知:外循环退出的临界点为i=n;所以总次数=n(n+1)得到执行次数为:n(n+1)

再举个例子
int sum = 0;
for(int i=1; i<n; i*=2)for(int j=0; j<i; j++)sum++;
求时间复杂度

先把内层看成O(1),那么外层循环次数为 log₂n,再看内层循环的 j 随运行次数变化:

t_n(项数)1234
j1248


得到j与tn的关系为:j=2tn得到总次数为等比数列求和,公比为2,首项为1,项数为tn−1:总次数=2tn−1−1已知:内循环退出的临界点为j=i,所以2tn=i,即tn=log2i,所以总次数=2log2i−1−1又已知:外循环退出的临界点为i=n;所以总次数=2log2n−1−1化简得总次数为:n/2−1;时间复杂度为O(n) 得到j与t_n的关系为:j = 2^{t_n} \\ 得到总次数为等比数列求和,公比为2,首项为1,项数为t_n-1:总次数= 2^{t_n -1} - 1\\ 已知:内循环退出的临界点为j = i,所以2^{t_n}=i,即t_n = log_2i,所以总次数= 2^{log_2i-1} - 1\\ 又已知:外循环退出的临界点为i = n;所以总次数=2^{log_2n-1} - 1 \\ 化简得总次数为:n/2-1;时间复杂度为O(n) 得到jtn的关系为:j=2tn得到总次数为等比数列求和,公比为2,首项为1,项数为tn1:总次数=2tn11已知:内循环退出的临界点为j=i,所以2tn=i,tn=log2i,所以总次数=2log2i11又已知:外循环退出的临界点为i=n;所以总次数=2log2n11化简得总次数为:n/21;时间复杂度为O(n)

小结

为了计算内层循环次数累加求和的项数,可以先把内层的时间复杂度看作O(1),然后计算这个条件下外层循环总次数,这样计算出来的外层循环总次数就是内层循环次数累加求和的项数了

再举个例子
for(i = n-1; i > 1; i--)for(j = 1; j < i; j++)if(A[j] > A[j+1])A[j] 和 A[j+1]对换

这个就相当于求最坏时间复杂度。

首先把内层看作O(1),那么外层循环次数为 (n-2),再看内层循环的 j 随运行次数变化:

t_n(项数)1234
jn-2n-3n-4n-51

所以可知:总次数是一个等差数列求和,首项为 (n-2) ,尾项为 1,项数为 (n-2)。

得到:
总次数=([(n−2)+1]∗(n−2))/2=(n−1)(n−2)/2时间复杂度为:O(n2) 总次数 = ([(n-2) + 1]*(n-2))/2 = (n-1)(n-2)/2 \\ 时间复杂度为: O(n^2) 总次数=([(n2)+1](n2))/2=(n1)(n2)/2时间复杂度为:O(n2)

多层循环的时间复杂度计算

从内到外进行计算,即内层的次数求和,求和项的项数为相对内层而言的外一层循环看作单层循环时的循环次数。从最内层开始计算,一层一层向外求和。

举例说明
for(i = 1; i <= n; i++) {             // 外层:n次for(j = 1; j <= i; j++) {         // 中层:i次for(k = 1; k <= j; k++) {     // 内层:j次// O(1)}}
}
  • 内层循环复杂度:
    O(j) O(j) O(j)

  • 中层循环总次数:
    ∑j=1ij=i(i+1)2=O(i2)\sum_{j=1}^{i} j = \frac{i(i+1)}{2} = O(i^2) j=1ij=2i(i+1)=O(i2)

  • 外层循环总次数:
    ∑i=1nO(i2)=O(∑i=1ni2)=O(n(n+1)(2n+1)6)=O(n3) \sum_{i=1}^{n} O(i^2) = O\left(\sum_{i=1}^{n} i^2 \right) = O\left(\frac{n(n+1)(2n+1)}{6}\right) = O(n^3) i=1nO(i2)=O(i=1ni2)=O(6n(n+1)(2n+1))=O(n3)

空间复杂度

空间复杂度S(n)定义为该算法所需的存储空间,它是问题规模n的函数。

算法的原地工作(In-place):是指算法在执行过程中,只使用常数级别的额外空间(通常是 O(1) 的额外空间),即除了输入数据本身占用的空间外,不需要额外申请大量存储空间。这样,算法直接在输入的数据结构上进行修改和操作,不借助辅助数组或数据结构。

原地算法的优点是节省内存资源,适合对空间要求较高的场景。例如,原地排序算法(如快速排序、堆排序)就是经典的原地工作的例子。

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

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

相关文章

12-大语言模型—Transformer 打地基,下游任务盖出百样房,指标来验收|下游任务白话指南

目录 1、核心逻辑&#xff1a;Transformer 的 “语言处理闭环” 2、转导与感知 → 模型咋 “理解语言”&#xff1f; 2.1、 人类 vs 机器的 “语言理解逻辑” 2.2、 自注意力机制&#xff1a;模型 “理解语言” 的数学核心 2.2.1、通俗拆解 2.2.1.1、是什么&#xff1f; …

深入探索爬虫与自动化脚本:释放效率的利器

在当今信息爆炸的时代&#xff0c;高效获取和处理数据已成为核心竞争力。爬虫与自动化脚本正是解决这一痛点的关键技术——它们如同数字世界的勤劳助手&#xff0c;帮我们自动完成繁琐重复的任务。下面我们来系统了解这两项技术的核心要点、应用场景和最佳实践。一、爬虫与自动…

React函数组件的“生活管家“——useEffect Hook详解

&#x1f3af; React函数组件的"生活管家"——useEffect Hook详解 1. &#x1f31f; 开篇&#xff1a;从生活中的"副作用"说起 嘿&#xff0c;各位掘友们&#xff01;今天咱们来聊聊React函数组件里的一个“大管家”——useEffect Hook。你可能会问&#x…

python基础:request请求Cookie保持登录状态、重定向与历史请求、SSL证书校验、超时和重试失败、自动生成request请求代码和案例实践

Cookie保持登录状态cookie session鉴权机制 cookie是由web服务器保存在用户浏览器&#xff08;客户端&#xff09;上的小文本文件&#xff0c;他可以包含有关用户的信息。无论何时用户访问到服务器&#xff0c;都会带上该服务器的cookie信息&#xff0c;一般cookie都是有有效期…

Vulkan入门教程 | 第二部分:创建实例

前言&#xff1a;本教程为笔者依据教程https://docs.vulkan.net.cn/spec/latest/index.html#_about进行Vulkan学习并结合自己的理解整理的笔记&#xff0c;供大家学习和参考。 &#xff08;注意&#xff1a;代码仅为片段&#xff0c;非完整程序&#xff09; 学习前提&#xff1…

PHP云原生架构:容器化、Kubernetes与Serverless实践

引言 随着云计算的普及,PHP应用也在向云原生架构演进。本文将深入探讨PHP在云原生环境中的最佳实践,包括容器化部署、Kubernetes编排、Serverless架构以及云原生监控与日志方案,帮助开发者构建现代化、可扩展的PHP应用。 容器化PHP应用 基础Dockerfile优化 # 多阶段构建…

【华为机试】5. 最长回文子串

文章目录5. 最长回文子串描述示例 1示例 2示例 3示例 4提示解题思路方法一&#xff1a;中心扩展法&#xff08;推荐&#xff09;方法二&#xff1a;动态规划方法三&#xff1a;Manacher算法方法四&#xff1a;暴力解法代码实现复杂度分析测试用例完整题解代码5. 最长回文子串 …

【图像处理基石】如何对遥感图像进行实例分割?

遥感图像实例分割是指在遥感影像中&#xff0c;不仅要识别出不同类别的目标&#xff08;如建筑物、车辆、道路等&#xff09;&#xff0c;还要区分同一类别中的不同个体&#xff08;如建筑物1、建筑物2&#xff09;&#xff0c;并为每个实例生成精确的像素级掩码。 一、遥感图…

电子电气架构 --- 软件bug的管理模式

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…

【每日一错】Oracle 19c CDB中如何启动一个PDB

文章目录题目扩展学习CDB与PDB的概念CDB&#xff0c;PDB结构优势总结题目 扩展学习 CDB与PDB的概念 在Oracle 12c及以上版本&#xff0c;Oracle引入了多租户架构&#xff0c;这种架构让数据库的管理和资源使用更加高效。它由两种主要组成部分组成&#xff1a; CDB&#xff0…

Android studio自带的Android模拟器都是x86架构的吗,需要把arm架构的app翻译成x86指令?

Android studio自带的Android模拟器都是x86架构的吗&#xff0c;需要把arm架构的app翻译成x86指令&#xff1f; deepseek回答&#xff1a; Android Studio 自带的官方模拟器&#xff08;Android Emulator&#xff09;主要提供基于 x86 架构的系统镜像。当运行 ARM 架构的应用…

Deep Learning_ Foundations and Concepts-Springer (2024)【拜读】20章3节

Diffusion Models 扩散模型 我们已经了解到&#xff0c;构建强大的生成模型的一种有效方法是&#xff1a;先引入一个关于潜在变量z的分布p(z)&#xff0c;然后使用深度神经网络将z变换到数据空间x。由于神经网络具有通用性&#xff0c;能够将简单固定的分布转化为关于x的高度灵…

Arduino与STM32:初学者该如何选择?

在电子爱好者和初学者的世界里&#xff0c;Arduino和STM32是两个经常被提及的名字。它们各自具有独特的优势和特点&#xff0c;适合不同类型的项目和需求。对于初学者来说&#xff0c;选择Arduino还是STM32&#xff0c;往往取决于个人的学习目标、项目需求以及预算。本文将详细…

创建型设计模式-工厂方法模式和抽象工厂方法模式

1、工厂方法模式 创建型设计模式之一 UML类图2、抽象工厂模式 也是创建型设计模式之一。虽然抽象工厂方法模式的类繁多&#xff0c;但是&#xff0c;主要分为4类。 AbstractFactory&#xff1a;抽象工厂角色&#xff0c;它声明了一组用于创建一种产品的方法&#xff0c;每一个方…

Hyperchain安全与隐私机制详解

一、核心安全机制1. 共识算法安全RBFT共识算法&#xff1a;改进型PBFT&#xff1a;基于PBFT算法优化&#xff0c;增加动态节点管理、失效数据恢复机制&#xff0c;提升系统容错性与可用性。性能指标&#xff1a;吞吐量稳定达3000-10000 TPS&#xff0c;交易执行时间控制在300ms…

Oracle优化学习十六

反连接反连接&#xff08;Anti Join&#xff09;是一种特殊的连接类型&#xff0c;与内连接和外连接不同&#xff0c;Oracle数据库里并没有相关的 关键字可以在SQL文本中专门表示反连接&#xff0c;所以这里把它单独拿出来说明。为了方便说明反连接的含义&#xff0c;我们用“t…

梳理一些 Docker 常用命令

以下是一些 Docker 常用命令&#xff0c;适用于日常开发、调试、部署等场景&#xff0c;分为几个常用类别&#xff1a;&#x1f4e6; 一、镜像&#xff08;Image&#xff09;相关命令命令说明docker images查看本地所有镜像docker pull <image>拉取镜像&#xff08;如 do…

C#_ArrayList动态数组

目录 ArrayList的特点 ArrayList 与普通数组的区别 使用示例&#xff1a; 普通数组 动态数组 主要方法和属性 属性&#xff1a; Count 获取动态数组的数据个数 读取某个位置的数据 // 索引 方法&#xff1a; Add 向集合末尾添加元素 Insert 在指定位置插入元…

Agent领域,近年来的前沿研究方向:多智能体协作、认知启发架构、伦理安全、边缘计算集成

Agent领域,近年来的前沿研究方向:多智能体协作、认知启发架构、伦理安全、边缘计算集成 在Agent领域,近年来的前沿研究方向主要集中在多智能体协作、认知启发架构、伦理安全、边缘计算集成以及生成式AI融合等方面。 一、多智能体协作与多模态任务 多智能体系统在复杂环境…

【安卓笔记】OOM与内存优化

0. 环境&#xff1a; 电脑&#xff1a;Windows10 Android Studio: 2024.3.2 编程语言: Java Gradle version&#xff1a;8.11.1 Compile Sdk Version&#xff1a;35 Java 版本&#xff1a;Java11 1.什么是OOM OOM即 OutOfMemoryError 内存溢出错误。常见于一些 资源型对…