【数据结构】复杂度

🔥博客主页:小王又困了
📚系列专栏:数据结构
🌟人之为学,不日近则日退
❤️感谢大家点赞👍收藏⭐评论✍️
目录
一、什么是数据结构
二、什么是算法
三、算法的效率
四、时间复杂度
4.1大O渐进表示法
4.2常见时间复杂度计算举例
4.3例题:消失的数字
五、空间复杂度
5.1空间复杂度计算
5.2例题:轮转数组
🗒️前言
在前面我们讲完了C语言的内容,从本期开始我们将进入数据结构的学习,本期介绍了数据结构的概念和算法分析的初步知识。
一、什么是数据结构
数据结构(Data Structure)是计算机存储、组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合。
二、什么是算法
算法(Algorithm)是定义良好的计算过程,它取一个或一组的值为输入,并产生出一个或一组值作为输出。简单来说算法就是一系列的计算步骤,用来将输入数据转化成输出结果。
三、算法的效率
我们会通过复杂度去衡量一个算法的好坏。算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源 。因此衡量一个算法的好坏,一般是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度。
时间复杂度主要衡量一个算法的运行快慢,而空间复杂度主要衡量一个算法运行所需要的额外空间。在计算机发展的早期,计算机的存储容量很小。所以对空间复杂度很是在乎。但是经过计算机行业的迅速发展,计 算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注一个算法的空间复杂度。
四、时间复杂度
时间复杂度的概念
时间复杂度的定义:在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。一 个算法执行所耗费的时间,从理论上说,是不能算出来的,只有你把你的程序放在机器上跑起来,才能知道。但是我们需要每个算法都上机测试吗?是可以都上机测试,但是这很麻烦,所以才有了时间复杂度这个 分析方式。一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法的时间复杂度。
即:找到某条基本语句与问题规模N之间的数学表达式,就是算出了该算法的时间复杂度。
4.1大O渐进表示法
实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,所以这里我们使用大O的渐进表示法。
大O符号:是用于描述函数渐进行为的数学符号。
推导大O阶方法:
1.用常数1取代运行时间中的所有加法常数。
2.在修改后的运行次数函数中,只保留最高阶项。
3.如果最高阶项存的系数不为1,则去除这个项的系数。
另外有些算法的时间复杂度存在最好、平均和最坏情况:
- 最坏情况: 任意输入规模的最大运行次数(上界)
- 平均情况: 任意输入规模的期望运行次数
- 最好情况: 任意输入规模的最小运行次数(下界)
说明:在实际中一般情况关注的是算法的最坏运行情况。
4.2常见时间复杂度计算举例
🚩冒泡排序:
// 计算BubbleSort的时间复杂度?
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(N)
最好情况就是数组本身有序,虽然它有序,但是计算机最初并不知道它是有序的,仍需要遍历一遍数组才能知道它是有序的,所以就好情况就是O(N)。
📒最坏情况:O(N^2)
最坏情况是数组完全逆序,则第一趟需要交换N − 1 次,第二趟需要交换N − 2次…直到最后一趟只交换一次,把所有的交换次数加起来就得到了冒泡排序最坏情况下的时间复杂度,其实也就是一个等差数列求和,所以最会情况下的时间复杂度是O(N^2)
🚩二分查找
// 计算BinarySearch的时间复杂度?
int BinarySearch(int* a, int n, int x)
{assert(a);int begin = 0;int end = n - 1;// [begin, end]:begin和end是左闭右闭区间,因此有=号while (begin <= end){int mid = begin + ((end - begin) >> 1);if (a[mid] < x)begin = mid + 1;else if (a[mid] > x)end = mid - 1;elsereturn mid;}return -1;
}
📒最好形况:O(1)
最好情况是第一次查找就找到目标值,此时时间复杂度就是O(1)。
📒最坏情况:O(log2N)
二分查找每次可以排出一半的数据,就坏的情况就是排出到只剩下一个数据。当N/2/2/2/2……/2=1时,就找到了目标值。除去了几个2就是执行的次数,所以时间复杂度为O(log2N)。
O(N)和O(log2N)的对比:
| N | 1000 | 100W | 10亿 |
| O(N) | 1000 | 100W | 10亿 |
| O(log2N) | 10 | 20 | 30 |
由此我们看到O(log2N)相对O(N)在效率上有很大的提升,但二分查找有一个限制条件就是数组必须有序,所以在实际中二分查找应用并不多。
🚩递归阶乘
// 计算阶乘递归Fac的时间复杂度?
long long Fac(size_t N)
{if (0 == N)return 1;return Fac(N - 1) * N;
}
📒时间复杂度:O(N)
Fac一共被递归调用了N+1次,且每次Fac中执行1次,总共执行N+1次,所以时间复杂度是O(N)。
🚩斐波那契数
// 计算斐波那契递归Fib的时间复杂度?
long long Fib(size_t N)
{if (N < 3)return 1;return Fib(N - 1) + Fib(N - 2);
}
📒时间复杂度:O(2^N)
斐波那契额数列,它的时间复杂度是等比数列求和,所以时间复杂度为O(2^N)。
4.3例题:消失的数字
💡思路一:
我们可以把0~N个数字全部加起来,减去数组中的元素,结果就是消失的数字。
时间复杂度为O(N)
int missingNumber(int* nums, int numsSize) {int i=0;int ret=N*N/2;for(i=0;i<numsSize;i++){ret-=nums[i];}return ret; }
💡思路二:
我们可以使用异或,异或的条件是相同为0,相异为1。两个相同的数异或为0,0和任何数异或都为原数,所以我们将0~N与数组中的所有异或,得到的结果就是消失的数。
int missingNumber(int* nums, int numsSize) {int m=0;int i=0;for(i=0;i<=numsSize;i++){m^=i;}for(i=0;i<numsSize;i++){m^=nums[i];}return m; }
五、空间复杂度
空间复杂度的概念:
空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度 。 空间复杂度不是程序占用了多少bytes的空间,而算的是变量的个数。 空间复杂度计算规则也使用大O渐进表示法。
注意:函数运行时所需要的栈空间(存储参数、局部变量、一些寄存器信息等)在编译期间已经确定好了,因此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定。
一般常见的空间复杂度都是O(1)或者O(N)(额外开辟数组)。
5.1空间复杂度计算
🚩递归阶乘:
// 计算阶乘递归Fac的空间复杂度?
long long Fac(size_t N)
{if(N == 0)return 1;return Fac(N-1)*N;
}
📒空间复杂度:O(N)
函数的每一次调用都会开辟一个栈帧,每个栈帧开常数个空间,开辟N+1个栈帧,空间复杂度就为O(N)。
递归程序最大的问题就是深度太深,会有栈溢出的风险。
🚩 斐波那契数
long long Fib(size_t N)
{if(N < 3)return 1;return Fib(N-1) + Fib(N-2);
}
📒空间复杂度:O(N)
空间是可以重复利用的,递归的调用是按一条线递归下去的,不会同时递归,当递归到最后一层返回时,创建的函数栈帧销毁,调用另一条仍可以使用这块空间,所以空间复杂度是O(N)。
5.2例题:轮转数组
💡思路
- 逆置前n-k个
- 逆置后k个
- 整体逆置
void reverse(int* nums,int left,int right)
{int tmp=0;while(left<=j){tmp=nums[left];nums[left]=nums[right];nums[right]=tmp;left++;right--; }
}void rotate(int* nums, int numsSize, int k)
{if(k==0){return nums;}reverse(nums,0,numsSize-1);reverse(nums,0,k%numsSize-1);reverse(nums,k%numsSize,numsSize-1);
}
本次的内容到这里就结束啦。希望大家阅读完可以有所收获,同时也感谢各位读者三连支持。文章有问题可以在评论区留言,博主一定认真认真修改,以后写出更好的文章。你们的支持就是博主最大的动力。
相关文章:
【数据结构】复杂度
🔥博客主页:小王又困了 📚系列专栏:数据结构 🌟人之为学,不日近则日退 ❤️感谢大家点赞👍收藏⭐评论✍️ 目录 一、什么是数据结构 二、什么是算法 三、算法的效率 四、时间复杂度 4.…...
【读点论文】PP-YOLOE: An evolved version of YOLO,面向友好部署的模型设计,为项目后续产业落地提供了更加有效的参考
PP-YOLOE: An evolved version of YOLO Abstract 在本报告中,我们介绍了PP-YOLOE,一种具有高性能和友好部署的工业最先进的目标探测器。我们在之前的PP-YOLOv2的基础上进行优化,采用无锚模式,更强大的骨干和颈部配备CSPRepResSt…...
微服务入门---SpringCloud(二)
微服务入门---SpringCloud(二) 1.Nacos配置管理1.1.统一配置管理1.1.1.在nacos中添加配置文件1.1.2.从微服务拉取配置 1.2.配置热更新1.2.1.方式一1.2.2.方式二 1.3.配置共享1)添加一个环境共享配置2)在user-service中读取共享配置…...
51单片机IO口控制
51单片机IO口控制 1.点亮LED灯 原理:根据电路图,指向IO口的引脚;拉低电平,灯亮、 如图: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zfco4IjK-1690308697530)(C:/Users/xie19/Pictur…...
ERROR 1064 - You have an error in your SQL syntax;
ERROR 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near (/, 少个逗号吧,以前开始写SQL,特别是修改SQL的时候容易出现这样错误。 而且自己也知道在附近…...
leetcode做题笔记46
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 思路一:回溯 void swap(int *nums,int index1,int index2) {int temp nums[index1];nums[index1] nums[index2];nums[index2] temp; }void prem(int* nu…...
快问快答JS面向对象面试题
1、说说你对闭包的理解 使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。在js中,函数即闭包,只有函数才会产生作用…...
googlenet论文理解
参考文章:https://www.cnblogs.com/czy4869/p/8977788.html 以及下面这篇的前几行让我弄懂了论文里说的稀疏性和计算性能兼顾:参考文章:https://blog.csdn.net/weixin_52121118/article/details/119740279...
OnnxRuntime TensorRT OpenCV::DNN性能对比(YoloV8)实测
1. 前言 之前把ORT的一套推理环境框架搭好了,在项目中也运行得非常愉快,实现了cpu/gpu,fp32/fp16的推理运算,同onnx通用模型在不同推理框架下的性能差异对比贴一下,记录一下自己对各种推理框架的学习状况 YoloV8模型大小 模型名称参数量NANO3.2M...... 2. CPU篇 CPU推理框架性…...
【QT 网络云盘客户端】——获取用户文件列表信息
目录 1.获取用户文件列表信息分析 2.设置图标属性 3.向服务器获取文件的数量 4.向服务器获取文件信息列表 4.显示图标 1.获取用户文件列表信息分析 1.将QListWidget设置为图标模式 2. 当我们点击"按下载量升序","按下载量降序",“更新” 菜单选项 都会…...
从0到1,无代码开发如何简化产品创新流程
在当今竞争激烈的市场环境中,产品创新已经成为企业成功的关键因素之一。为了在市场上保持竞争力,企业需要不断地推出新产品或改进现有产品。然而,传统的开发流程往往耗时费力,且成本高昂。因此,简化产品创新流程成为了…...
select、epoll 的快速核心理解
一、 select 最low的就是在用户代码中自旋实现所有阻塞socket的监听。但是每次判断socket是否产生数据,都涉及到用户态到内核态的切换。 于是select改进:将fd_set传入内核态,由内核判断是否有数据返回; 然后最low的只能使用自旋…...
HTTP和HTTPS的区别
一、两者概念 1.1 HTTP概念 HTTP 的全称是超文本传输协议(HyperText Transfer Protocol) 是一种用于分布式、协作式和超媒体信息系统的应用协议,简单来说就是一种分布和接收HTML页面的方法,被用于在Web浏览器和网站服务器之间传递…...
分布式异步任务处理组件(二)
一些关键点的设计脑暴记录----very important!!! 首先,任务存储交给kafka,由节点负责写入kafka,acks1;失败重试;透传kafka的提交可靠性,保证任务提交成功;后…...
Jenkins 拉取 GitHub 私有仓库失败问题
添加仓库的时候提示 stderr: fatal: Cannot prompt because user interactivity has been disabled. 把在 GitHub账户设置中生成的个人访问令牌填到地址里...
小程序 多层次对象数组的赋值、动态赋值
1、给对象赋值 data: {form: {Name: ,IDCard: ,Sex: ,}},对单个属性赋值 this.setData({form.Name:章三,[form.Sex]:女,}) 动态赋值 onChangeDate(e) {let field e.currentTarget.dataset.field;this.setData({[form.${field}]: e.detail.data})}, field 是wxml上通过dat…...
angular踩坑
1 新版路由守卫由于canActivate已被废弃,采用函数函数,但其参数中无法像类一样进行路由对象注入,如何实现路由首位中的页面跳转? import { CanActivateFn,Router,ActivatedRouteSnapshot, RouterStateSnapshot,} from angular/ro…...
C#时间轴曲线图形编辑器开发1-基本功能
目录 一、前言 1、简介 2、开发过程 3、工程下载链接 二、基本功能实现 1、绘图面板创建 (1)界面布置 (2)显示面板代码 (3) 面板水平方向、竖直方向移动功能实现 (4)面板放…...
elasticsearch查询操作(DSL语句方式)
说明:本文介绍在kibana,es的可视化界面上对文档的查询操作; 添加数据 先使用API,创建索引库,并且把数据从MySQL中查出来,传到ES上,参考(http://t.csdn.cn/NaTHg) 索引库…...
JavaScript详解
目录 一、JavaScript是什么? 1.1、JavaScript 和 HTML 和 CSS 之间的关系 1.2、JavaScript 运行过程 1.3、JavaScript 的组成 二、JavaScript 的书写形式 1. 行内式 2. 内嵌式 3、外部式 注释 三、输入输出 输入: prompt 输出: alert 输出: …...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
Python实现简单音频数据压缩与解压算法
Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...
DAY 26 函数专题1
函数定义与参数知识点回顾:1. 函数的定义2. 变量作用域:局部变量和全局变量3. 函数的参数类型:位置参数、默认参数、不定参数4. 传递参数的手段:关键词参数5 题目1:计算圆的面积 任务: 编写一…...
jdbc查询mysql数据库时,出现id顺序错误的情况
我在repository中的查询语句如下所示,即传入一个List<intager>的数据,返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致,会导致返回的id是从小到大排列的,但我不希望这样。 Query("SELECT NEW com…...
