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

初识数据结构--时间复杂度 和 空间复杂度

数据结构前言

数据结构

数据结构是计算机存储、组织数据的方式(指不仅能存储数据,还能够管理数据-->增删改)。指相互之间存在一种或多种特定关系的数据元素的集合。没有单一的数据结构对所有用途都有用,所以我们要学习各种的数据结构,比如:线性表、树、图、哈希等


算法

其实算法就在我们身边。这就好像是给你一道题,怎么去实现它。

算法:就是定义良好的计算过程,他取⼀个或⼀组的值为输⼊,并产⽣出⼀个或⼀组值作为 输出。简单来说算法就是⼀系列的计算步骤,⽤来将输⼊数据转化成输出结果


算法效率

那么任何衡量一个算法的好坏呢?

案例:旋转数组
思路:循环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;}
}

 

 

代码在力扣点击执行可以通过,但是点提交却无法通过,那怎么衡量呢?

这就要给大家提出复杂度的概念。


复杂度的概念

算法在编写成为可执行程序后,运行时需要耗费时间资源和空间(空间)资源。因此衡量一个算法的好坏,一般是通过时间和空间俩个维度来衡量的,既时间复杂度空间复杂度

时间复杂度主要衡量⼀个算法的运⾏快慢,⽽空间复杂度主要衡量⼀个算法运⾏所需要的额外空间。在计算机发展的早期,计算机的存储容量很⼩。所以对空间复杂度很是在乎。但是经过计算机⾏业的 迅速发展,计算机的存储容量已经达到了很⾼的程度。所以我们如今已经不需要再特别关注⼀个算法 的空间复杂度。

总的来说:虽然现在计算机的存储容量已经变的很大了,但是也不能随意的浪费


时间复杂度

定义:在计算机科学中,算法的时间复杂度是⼀个函数式T(N),它定量描述了该算法的运⾏时间。时间复杂度是衡量程序的时间效率,那么为什么不去计算程序的运⾏时间呢?

1. 因为程序运⾏时间和编译环境和运⾏机器的配置都有关系,⽐如同⼀个算法程序,⽤⼀个⽼编译 器进⾏编译和新编译器编译,在同样机器下运⾏时间不同。

2. 同⼀个算法程序,⽤⼀个⽼低配置机器和新⾼配置机器,运⾏时间也不同。

3. 并且时间只能程序写好后测试,不能写程序前通过理论思想计算评估。

对于定义大家了解一下就行。

大家只要知道时间复杂度是用来计算程序的执行次数 。

案例:

// 请计算⼀下Func1中++count语句总共执⾏了多少
次?
void Func1(int N)
{int count = 0;for (int i = 0; i < N ; ++ i){for (int j = 0; j < N ; ++ j){++count;}}for (int k = 0; k < 2 * N ; ++ k){++count;}int M = 10;while (M--){++count;}
}

Func1执行的基本操作次数:T(N) = N² + 2 * N + 10

因为第一个for循环中还嵌套了一个for循环,就是当 i = 0 时, j 就要循环N次 ,当 i = 1, j 就要循环N次 ...... ,这样就是N²。

然后下一个for循环是和第一个for 循环时并列的,所以相加。

最后一个循环了10次,所以相加10。

影响时间复杂度的条件有:

每条语句的执行时间 * 每条语句的执行次数

但是每条语句的执行时间无法给出准确的数据。得出结论:每条语句的执行时间即使有差别,但是微乎其微,可以忽略不计,认为每条语句的执行时间是相同的。

实际中我们计算时间复杂度时,计算的也不是程序的精确的执⾏次数,精确执⾏次数计算起来还是很 ⿇烦的(不同的⼀句程序代码,编译出的指令条数都是不⼀样的),计算出精确的执⾏次数意义也不⼤。,所以我们只需要计算程序能代表增⻓量 级的⼤概执⾏次数,复杂度的表⽰通常使⽤⼤O的渐进表⽰法。

 

Func1的时间复杂度为O(N²)。 

时间复杂度函数式T(N)中,只保留最⾼阶项,去掉那些低阶项,因为当N不断变⼤时, 低阶项对结果影响越来越⼩,当N⽆穷⼤时,就可以忽略不计了 


 大O渐进表⽰法

1. 时间复杂度函数式T(N)中,只保留最⾼阶项,去掉那些低阶项,因为当N不断变⼤时, 低阶项对结果影响越来越⼩,当N⽆穷⼤时,就可以忽略不计了

2. 如果最⾼阶项存在且不是1,则去除这个项⽬的常数系数,因为当N不断变⼤,这个系数 对结果影响越来越⼩,当N⽆穷⼤时,就可以忽略不计了。

3. T(N)中如果没有N相关的项⽬,只有常数项,⽤常数1取代所有加法常数。


 时间复杂度计算示例

示例1:

void Func2(int N)
{int count = 0;for (int i = 0; i < 2 * N; i++){++count;}int m = 10;while (m--){++count;}
}

 Func2执⾏的基本操作次数: T (N) = 2N + 10

根据推导规则第1条得出

Func2的时间复杂度为: O(N)


 示例2:

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

Func3执⾏的基本操作次数:

T (N) = M + N

因此:Func2的时间复杂度为: O(M + N)

因为在这边M 和 N都是变量,都得保留。


示例3:

void Func4(int N)
{int count = 0;for (int i = 0; i < 100; i++){++count;}printf("%d\n", count);}

T (N) = 100

根据推导规则第3条得出

Func2的时间复杂度为: O(1)


 示例4:

const char * strchr ( const char
* str, int character)
{const char* p_begin = s;while (*p_begin != character){if (*p_begin == '\0')return NULL;p_begin++;}return p_begin;
}

 strchr执⾏的基本操作次数:

1)若要查找的字符在字符串第⼀个位置,则: T (N) = 1

2)若要查找的字符在字符串最后的⼀个位置, 则: T (N) = N

3)若要查找的字符在字符串中间位置,则: T (N) = N / 2

因此:strchr的时间复杂度分为:

最好情况: O(1)

最坏情况: O(N)

平均情况: O(N)

总结 通过上⾯我们会发现,有些算法的时间复杂度存在最好、平均和最坏情况。

最坏情况:任意输⼊规模的最⼤运⾏次数(上界)

平均情况:任意输⼊规模的期望运⾏次数

最好情况:任意输⼊规模的最⼩运⾏次数(下界)

⼤O的渐进表⽰法在实际中⼀般情况关注的是算法的上界,也就是最坏运⾏情况


 空间复杂度

空间复杂度也是⼀个数学表达式,是对⼀个算法在运⾏过程中因为算法的需要额外临时开辟的空间。

 空间复杂度计算规则基本跟实践复杂度类似,也使⽤⼤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;}
}

函数栈帧在编译期间已经确定好了, 只需要关注函数在运⾏时额外申请的 空间。

BubbleSort额外申请的空间有 exchange等有限个局部变量,使⽤了 常数个额外空间

因此空间复杂度为 O(1)。


示例2:

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

Fac递归调⽤了N次,额外开辟了N个函数栈帧, 每个栈帧使⽤了常数个空间

因此空间复杂度为: O(N)

 


 常见复杂度对比

大家可以看到当趋近于无穷时, n ! > 3 ^n > x² > ln(x) > sinx 

希望对大家有所帮助。 

相关文章:

初识数据结构--时间复杂度 和 空间复杂度

数据结构前言 数据结构 数据结构是计算机存储、组织数据的方式(指不仅能存储数据&#xff0c;还能够管理数据-->增删改)。指相互之间存在一种或多种特定关系的数据元素的集合。没有单一的数据结构对所有用途都有用&#xff0c;所以我们要学习各种的数据结构&#xff0c;比…...

Ubuntu QT 交叉编译环境搭建

文章目录 下载安装qtCreatornot a valid identifier 的错误 安装g下载并安装交叉编译器下载交叉编译器安装交叉编译器 下载编译 ARM 的Qt平台源码配置arm的QT平台 下载安装qtCreator 去QT下载官网下载对应需要的QT软件。 这里下载5.12.96版本的 改变安装包权限&#xff0c;…...

C语言中缓冲区底层实现以及数据输入的处理

C语言中缓冲区底层实现以及数据输入的处理 一、缓冲区的概念 在C语言的标准输入输出操作中&#xff0c;缓冲区&#xff08;Buffer&#xff09; 扮演着至关重要的角色。在计算机系统中&#xff0c;缓冲区是一块用于暂存数据的内存区域。在输入输出&#xff08;I/O&#xff09;…...

RocketMQ事务消息原理

一、RocketMQ事务消息原理&#xff1a; RocketMQ 在 4.3 版本之后实现了完整的事务消息&#xff0c;基于MQ的分布式事务方案&#xff0c;本质上是对本地消息表的一个封装&#xff0c;整体流程与本地消息表一致&#xff0c;唯一不同的就是将本地消息表存在了MQ内部&…...

【Java】IntelliJ IDEA开发环境安装

一、下载 官方地址&#xff1a;https://www.jetbrains.com/idea/ 点击Download直接下载 二、安装 双击安装包&#xff0c;点击Next 选择安装路径&#xff0c;点击Next 勾选安装内容 安装完成。 三、创建项目 打开IDEA&#xff0c;填写项目名称&#xff0c;选择项目安装路径…...

Go语言中的通道 (Channel) 实践:Goroutine之间的通信

1. 引言 在Go语言中&#xff0c;并发编程是其核心优势之一。与其他编程语言不同&#xff0c;Go语言推荐使用通道 (Channel) 来进行多线程或并发任务的协调与通信&#xff0c;而非使用锁机制。本文将介绍如何通过通道在多个goroutine之间进行通信&#xff0c;避免竞争条件和复杂…...

常用类(二)--String类的简单总结

文章目录 1.基本介绍1.1创建对象1.2找到对应下标的字符1.3找到对应字符的下标1.4指定位置开始遍历1.5反向进行遍历1.6大小写之间的转换1.7字符串转换为数组1.8元素的替换1.9字符串的分割1.10字符串的截取 2.StringBuilder和StringBuffer2.1 StringBuilder的引入2.2面试题目 1.基…...

Spring Boot开发:从入门到精通

Spring Boot开发&#xff1a;从入门到精通 当你在开发一个新的Java应用时&#xff0c;是否曾经感到苦恼于繁琐的配置和重复的代码&#xff1f;Spring Boot就像一位友好的助手&#xff0c;向你伸出援手&#xff0c;让开发变得轻松愉快。从这一单一框架中&#xff0c;你可以快速…...

《数据结构》--队列【各种实现,算法推荐】

一、认识队列 队列是一种常见的数据结构&#xff0c;按照先进先出&#xff08;FIFO&#xff0c;First In First Out&#xff09;的原则排列数据。也就是说&#xff0c;最早进入队列的元素最先被移除。队列主要支持两种基本操作&#xff1a; 入队&#xff08;enqueue&#xff0…...

面试八股文对校招的用处有多大?--GDB篇

前言 1.本系列面试八股文的题目及答案均来自于网络平台的内容整理&#xff0c;对其进行了归类整理&#xff0c;在格式和内容上或许会存在一定错误&#xff0c;大家自行理解。内容涵盖部分若有侵权部分&#xff0c;请后台联系&#xff0c;及时删除。 2.本系列发布内容分为12篇…...

Unity用VS打开FGUI脚本变成杂项怎么处理?

在Unity中使用Visual Studio&#xff08;VS&#xff09;打开FGUI脚本时&#xff0c;如果脚本显示为杂项文件&#xff0c;这通常意味着VS没有正确识别或关联这些脚本文件。以下是一些解决此问题的步骤&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&#xff0c;大家…...

交叉熵损失函数(Cross-Entropy Loss Function)解释说明

公式 8-11 的内容如下&#xff1a; L ( y , a ) − [ y log ⁡ a ( 1 − y ) log ⁡ ( 1 − a ) ] L(y, a) -[y \log a (1 - y) \log (1 - a)] L(y,a)−[yloga(1−y)log(1−a)] 这个公式表示的是交叉熵损失函数&#xff08;Cross-Entropy Loss Function&#xff09;&#…...

和外部机构API交互如何防止外部机构服务不可用拖垮调用服务

引言 在现代的分布式系统和微服务架构中&#xff0c;服务之间的通信往往通过API进行&#xff0c;尤其是在与外部机构或第三方服务进行交互时&#xff0c;更需要通过API实现功能的集成。然而&#xff0c;由于外部服务的可控性较差&#xff0c;其服务的不可用性&#xff08;如响…...

自动猫砂盆真的有必要吗?买自动猫砂盆不看这四点小心害死猫。

现在越来越多铲屎官选择购买自动猫砂盆来代替自己给猫咪铲屎&#xff0c;可是自动猫砂盆真的有必要吗&#xff1f;要知道&#xff0c;在现在忙碌的生活中&#xff0c;有很多人因为工作上的忙碌而不小心忽视了猫咪&#xff0c;猫咪的猫砂盆堆满粪便&#xff0c;要知道猫砂盆一天…...

国外解压视频素材哪里找?五个海外解压视频素材网站推荐

国外解压视频素材哪里找&#xff1f;五个海外解压视频素材网站推荐 如果你正在寻找国外的解压视频素材&#xff0c;那么今天这篇文章一定能帮助你。无论是修牛蹄、洗地毯&#xff0c;还是切肥皂、玩解压游戏等&#xff0c;下面分享的几个网站都是你找到高质量海外解压视频素材…...

Android一个APP里面最少有几个线程

Android一个APP里面最少有几个线程 参考 https://www.jianshu.com/p/92bff8d6282f https://www.jianshu.com/p/8a820d93c6aa 线程查看 Android一个进程里面最少包含5个线程&#xff0c;分别为&#xff1a; main线程(主线程&#xff09;FinalizerDaemon线程 终结者守护线程…...

位操作解决数组的花样遍历

文章目录 题目 一、思路&#xff1a; 二、代码 总结 题目 leetcodeT289 https://leetcode.cn/problems/game-of-life/description/ 一、思路&#xff1a; 这题思路很简单&#xff0c;对每个位置按照题目所给规则进行遍历&#xff0c;判断周围网格的活细胞数即可。但是题目要求…...

【面试宝典】深入Python高级:直戳痛点的题目演示(下)

目录 &#x1f354; Python下多线程的限制以及多进程中传递参数的⽅式 &#x1f354; Python是如何进⾏内存管理的&#xff1f; &#x1f354; Python⾥⾯如何拷⻉⼀个对象&#xff1f; &#x1f354; Python⾥⾯search()和match()的区别&#xff1f; &#x1f354; lambd…...

Hive数仓操作(十七)

一、Hive的存储 一、Hive 四种存储格式 在 Hive 中&#xff0c;支持四种主要的数据存储格式&#xff0c;每种格式有其特点和适用场景&#xff0c;不过一般只会使用Text 和 ORC &#xff1a; 1. Text 说明&#xff1a;Hive 的默认存储格式。存储方式&#xff1a;行存储。优点…...

工业和自动化领域常见的通信协议

在工业和自动化领域&#xff0c;有多种常见的通信协议&#xff0c;主要用于设备间的通信、数据传输和控制。 Modbus&#xff1a; 类型&#xff1a;串行通信协议用途&#xff1a;广泛用于工业自动化设备间的通信&#xff0c;如PLC、传感器和执行器。优点&#xff1a;简单、开放且…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用

一、方案背景​ 在现代生产与生活场景中&#xff0c;如工厂高危作业区、医院手术室、公共场景等&#xff0c;人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式&#xff0c;存在效率低、覆盖面不足、判断主观性强等问题&#xff0c;难以满足对人员打手机行为精…...