当前位置: 首页 > news >正文

数据结构之复杂度

数据结构的理解

数据本身是杂乱无章的,需要结构进行增删查改等操作更好的管理数据;

比如:在程序中需要将大量的代码(数据)通过结构进行管理;
再比如:定义1000个整型变量的数组,我们可以对数组进行删除某一个数据,在某一个数据后面插入新的数据等等操作。这些都是数据结构的体现。

数据结构是用来在计算机中存储和管理数据的,这种存储和管理的方式有很多种,我们后面会一一学到比如:线性表、数、图、哈希等

数组是最基础的数据结构;

算法理解

算法是一个良好计算的过程,我们可以将数据结构作为放着数据的容器,而算法就是用来如何才能让我们良好的从容器中获取和管理数据的这么一个过程就叫做算法

因此:有数据结构的地方就有算法,数据结构和算法不分家

算法重要性

在笔试和面试中是必考的,是以编程题的形式进行考察,我们要好好磨砺算法,做到手撕代码 <:

学好算法秘籍:

1.死磕代码
2.遇到算法题莫慌,带着思考进行画图。
3.看关于算法和数据结构的书藉
4.使用各大OJ平台进行刷题(用OJ平台刷题的魅力:只需要写入内部的逻辑代码即可,其他的平台都已经定义好了)

自己下去将轮转数组进行单独实现
如何衡量算法的好坏呢? ----->用复杂度进行衡量

复杂度理解

而复杂度又包含时间复杂度和空间复杂度
时间复杂度主要衡量一个算法的运行快慢;
空间复杂度主要衡量一个算法运行所需要的额外空间
随着时代的发展,我们对空间的关注已经不是大头了,时间才是,注意不是不关注!(也就是摩尔定律)

时间复杂度理解

时间复杂度是一个函数表达式T(N),这个与数学中的定义的一次函数和二次函数是一样的,它是用来衡量程序的运行效率。它是一个粗估的值,不是精确的值。
为什么不去计算程序的运行时间呢?

1.因为程序的运行时间和编译环境和运行机器的配置都有关系,
比如:同一个算法程序,用一个老的编译器进行编译和新的编译器编译,在同样的运行机器下程序运行时间不同
2.同一个算法程序,在不同的运行机器下(在一个老低配置机器和新高配置机器的情况下)使用同一个编译器进行编译,程序运行时间也会不一样
3. 并且计算程序的运行时间只能在程序运行之后才能知道,不能在写程序之前就知道大概的运行时间是多少。

总结:程序的运行时间是不确定的

时间复杂度T(N)到底怎么去计算呢?
T(N) = 每条语句的运行时间 * 运行次数
前面我们知道运行时间是不确定的,所以将运行时间去掉,所以
T(N) = 程序的运行次数

在这里插入图片描述

这个程序的时间复杂度T(N) = N^2 + 2N + 10
因为2N + 10 对时间复杂度的影响很小,所以忽略不计,最终:T(N) = N^2

因此,对于时间复杂度来说,是一个粗估的值,争对这种情况,我们有了大O的渐进表示法的计算法则进行计算

大O的渐进表示法

大O的计算规则:

  1. 时间复杂度T(N) 中,只保留最高项,去掉最低项,包括常数项
  2. 如果最高项的常数系数存在且不是1,则去除这个项目的常数系数
  3. 如果T(N) 中只有常数项,用常数1代表所有的加法常数。 O(1)来表示

判断高阶项的方法:对结果影响最大就是高阶项

大O的渐进表示法在空间和时间上都可以用
时间复杂度举例:

以下是常见时间复杂度的计算:

在这里插入图片描述
T(N) = 2N + 10 根据法则2:O(N)
在这里插入图片描述
如果T(N) 中存在两个变量,不确定这两个变量的大小,则这两个变量都可以表示,例如:O(M + N), M 和 N 都是变量,具体看题目中是如何定义M和N 的大小,比如:M >> N, 则为O(M),反之则为O(N);在有一种情况就是M == N, 则为O(M+N)。
在这里插入图片描述
T(N) = 100, 根据法则3:O(1)

请写出查找字符长度的时间复杂度
在这里插入图片描述

这里T(N) 的大小取决于你所要查找的位置,
比如:
查找的字符的位置在最后一个位置,则为O(N)
查找的字符的位置在第一个位置,则为O(1)
查找的字符的位置在中间位置,则为O(1/2 * N) = O(N)

最好情况: O(1)
最坏情况: O(N)
平均情况: O(N)

总结 通过上面我们会发现,有些算法的时间复杂度存在最好、平均和最坏情况。 最坏情况:任意输入规模的最大运行次数(上界)
平均情况:任意输入规模的期望运行次数 最好情况:任意输入规模的最小运行次数(下界)
大O的渐进表示法在实际中一般情况关注的是算法的上界,也就是最坏运行情况。

在看看冒泡排序的时间复杂度:
在这里插入图片描述
因此,我们取得是上界的情况:O(N^2)

再看看这道题
在这里插入图片描述

这里需要注意的是:
课件中和书籍中 log2 n 、 log n 、 lg n 的表示
当n接近⽆穷⼤时,底数的⼤⼩对结果影响不⼤。因此,⼀般情况下不管底数是多少都可以省略不 写,即可以表⽰为 log n
不同书籍的表⽰⽅式不同,以上写法差别不⼤,我们建议使⽤ log n
还有一个原因是:键盘中敲不出底数

在这里插入图片描述

到这里时间复杂度的计算就够够用了

空间复杂度

空间复杂度计算规则基本跟时间复杂度类似,也使⽤⼤O渐进表⽰法。
注意:我们计算空间复杂度时只计算函数运⾏时所需要的栈空间,存储参数、局部变量、⼀些寄存器信息和非递归函数调用的栈帧等都是在函数运行时的内容。
因此空间复杂度主要通过函数在运⾏时候显式申请的额外空间来确定,也就是函数定义的下面那一部分

以下是常见的空间复杂度的计算:
在这里插入图片描述
在这里插入图片描述

常见的空间复杂度计算

通过动态内存申请内容也会涉及到空间复杂度的计算
例如:
在这里插入图片描述

常⻅复杂度对⽐:

在这里插入图片描述
在这里插入图片描述
总结:随着n的增加,各种的复杂度的变化趋势也大不相同;随着n的增加,变化越缓的复杂度代表着在程序运行时的效率高;越陡的效率低

关于复杂度的相关算法题:

轮转数组

思路1:

	时间复杂度 O(n^2)循环K次将数组所有元素向后移动⼀位(代码不通过)

在这里插入图片描述

核心代码如下:

void rotate(int* nums, int numsSize, int k) {while(k--)//直到轮转结束后就停止{int end = nums[numsSize-1];for(int i = numsSize - 1; i > 0; i--)//这里是整体向后移的操作,起始位置在最后一位,直到将第一个数据移到第二位后就结束{nums[i] = nums[i - 1];//将一位的数据移到后一位}nums[0] = end;//将最后的移到第一位}
}

在这里插入图片描述

思路2:

空间复杂度 O(n)
申请新数组空间,先将后k个数据放到新数组中,再将剩下的数据挪到新数组中
在这里插入图片描述

核心代码:

void rotate(int* nums, int numsSize, int k) {int NewArr[numsSize];for(int i = 0; i < numsSize; i++){NewArr[(k + i) % numsSize] = nums[i];//这里是将原数组中的数据放入到新数组下标为(k + i) % numsSize中}for(int i = 0; i < numsSize; i++){nums[i] = NewArr[i]; //再放到原数组中去}}

思路3:


文章转载自:

http://DRM21RG7.prqdr.cn
http://ep6GedoT.prqdr.cn
http://k2HH9Bkc.prqdr.cn
http://E8vO3OFj.prqdr.cn
http://eugSwYkc.prqdr.cn
http://9J7sNcKW.prqdr.cn
http://XEyw7W0p.prqdr.cn
http://GKMWHi9C.prqdr.cn
http://hUcGg9Jn.prqdr.cn
http://KMAjKjtz.prqdr.cn
http://kb2sxQvG.prqdr.cn
http://19DrdIg7.prqdr.cn
http://fYU12kt3.prqdr.cn
http://CW51iEbb.prqdr.cn
http://wWT0u27Q.prqdr.cn
http://DBraa5Ib.prqdr.cn
http://j4zJktPK.prqdr.cn
http://daGNU3O0.prqdr.cn
http://ezBpGRGT.prqdr.cn
http://A6fCcaGp.prqdr.cn
http://1649zM3L.prqdr.cn
http://Pw19dvMD.prqdr.cn
http://Rj3XxnRx.prqdr.cn
http://cYcEfO7G.prqdr.cn
http://VCfUkIsl.prqdr.cn
http://jwp76X3C.prqdr.cn
http://exT6wbmT.prqdr.cn
http://wy3bG088.prqdr.cn
http://dppPOIoI.prqdr.cn
http://scJj3JKo.prqdr.cn
http://www.dtcms.com/a/378672.html

相关文章:

  • 几种常用锁
  • android13修改WiFi扫描二维码识别识别成功率不高的问题
  • params和body传参讲解
  • 单片机学习笔记
  • 图卷积神经网络(GCN)学习笔记
  • MySQL执行过程中如何选择最佳的执行路径
  • 牛客周赛 Round 108(思维、位运算、DP、SOSDP)
  • 插槽 el-input 数据双向 绑定失效 响应式更新失败
  • 代码随想录算法训练营第58天 | 拓扑排序精讲、dijkstra(朴素版)精讲
  • 揭秘KafkaStreams 线程缓存:NamedCache深度解析
  • 中标麒麟7.4部署gitlab-runner
  • Shopify指纹手机矩阵:无限扩店,横扫FB/GG广告封号风险
  • react context如何使用
  • npm是什么?优缺点又是什么?
  • ubuntu24.04+5070ti训练yolo模型(2)
  • [SQL]查询SSMS当前连接数据库列表
  • 乾博绝缘监测仪为水泥厂安全生产护航
  • JVM(jdk1.8) 实战
  • 设计模式(C++)详解—工厂方法模式(2)
  • 自动化运维实践:SaaS系统Nginx配置文件自动化运维脚本详解
  • 3D模型快速混沌加密matlab完整代码
  • 敏捷实践指南(中文版):章节梳理/主要知识体系和知识点
  • 第一章 ELK Stack基础概念与架构
  • GraphQL RPC 与通用索引器公测介绍:为 Sui 带来更强大的数据层
  • ShardingSphere 分库分表技术实现与实战案例
  • Docker 部署 MongoDB:单节点与副本集的最佳实践
  • OCR 识别表现好坏离不开什么?
  • 阿里云ACA认证[特殊字符]阿里云ACP认证
  • 计算机网络实验00---环境准备
  • 【路由交换技术】基于eNSP的多子网路由互通实验:从配置到验证的全流程指南