【数据结构与算法篇】之时间复杂度与空间复杂度
【数据结构与算法篇】之时间复杂度与空间复杂度
- 一、时间复杂度
- 1.1时间复杂度的定义
- 1.2 常见的时间复杂度的计算
- 1.3 常见的函数的时间复杂度
- 二、空间复杂度

❤️博客主页: 小镇敲码人
🍏 欢迎关注:👍点赞 👂🏽留言 😍收藏
🌞友友们暑假快乐,好久不见呀!!!💖💖💖
🍉 有人曾经问过我这样一个问题,“人终其一身,执着追求的东西究竟是什么?”我是这样回答的,”我们终其一生都在寻找着那个和我们灵魂极其契合的人,可最后才发现,那个人只有也只能是自己,学会在无聊时消遣自己是非常重要的“,所以无论目前屏幕上的你深处怎样的绝境之中,请不要放弃自己,好好的爱自己就是度过绝境的最佳武器!!!😸😸😸
一、时间复杂度
1.1时间复杂度的定义
在计算机与科学中,算法的时间复杂度(time complexity)是一个函数,它定性的描述算法的运行时间,表示一个程序来回执行的次数,但不定量。这个函数的自变量是算法输入值的字符串的长度,即 N N N。时间复杂度常用大O符号表述,只包括那个幂次最高的项数。使用这种方式时,时间复杂度可被称为是渐近的,也就是 lim N → ∞ O ( N ) \lim\limits_{N\rarr\infin}O(N) N→∞limO(N)时的情况。例如,如果一个算法对于任何大小为 N N N的输入,它至多需要 5 N 3 N^3 N3 + 3 N 3N 3N 的时间运行完毕,那么它的渐近时间复杂度是 O ( N 3 ) O(N^3) O(N3)。
- 注意:时间复杂度不计算时间,只计算程序的执行次数。
常见的时间复杂度包括:
- 常数时间复杂度( O ( 1 ) ) O(1)) O(1)):算法的执行时间与输入规模无关,常数级别的执行时间。
- 线性时间复杂度( O ( N ) O(N) O(N)):算法的执行时间与输入规模线性相关,随着输入规模的增加而线性增长。
- 对数时间复杂度( O ( l o g N ) O(log N) O(logN)):算法的执行时间与输入规模的对数关系,通常是二分查找等算法的时间复杂度。
- 平方时间复杂度( O ( N 2 ) O(N^2) O(N2)):算法的执行时间与输入规模的平方相关,通常是嵌套循环等算法的时间复杂度。
- 线性对数时间复杂度 ( O ( N ∗ l o g N ) ) (O(N*log N)) (O(N∗logN)) :它表示随着输入规模 N 的增加,算法的执行时间以 N 乘以 log N 的速度增长,线性对数时间复杂度常常出现在一些高效的排序算法(如快速排序和归并排序)以及一些分治算法中。
注意:嵌套循环的算法时间复杂度不一定是 O ( N 2 ) O(N^2) O(N2)。
通过分析算法的时间复杂度,我们可以更好地理解算法的性能特点,并进行算法的选择和优化。
1.2 常见的时间复杂度的计算
1.2.1 常数时间复杂度( O ( 1 ) ) O(1)) O(1))
int main(){int a = 0;a += 1;printf("%d",&a);return 0;}
这段代码执行了四次操作。我们逐行分析代码的执行过程:
1.int a = 0;
:这行代码初始化了整数变量a,将其赋值为 0。
2. a += 1;
:这行代码将变量 a的值增加 1,现在 a 的值为 1。
3.printf("%d", &a);
:这行代码使用 printf 函数打印变量 a 的值的内存地址,格式化输出为十进制整数。
4. return 0;
:在 main 函数的结尾,使用 return 语句将返回值设为 0。
因此,代码执行了四次操作。
- 若对于一个算法 T ( n ) T(n) T(n)的上界与输入大小无关,则称其具有常数时间,记作O(1)时间,故而这个算法的时间复杂度为 O ( 1 ) O(1) O(1)。
1.2.2 线性时间复杂度( O ( N ) O(N) O(N))
int main()
{int n = 0;scanf("%d",&n);int sum = 1;for(int i = 1;i < n;;i++)sum *= i;printf("%d",sum);return 0;
}
这段代码的执行过程如下:
int n = 0;
:这行代码声明了一个整数变量 n,并将其初始化为 0。scanf("%d",&n);
:这行代码使用 scanf 函数从标准输入中读取一个整数,并将其赋值给变量 n。int sum = 1;
:这行代码声明了一个整数变量 sum,并将其初始化为 1。for(int i = 1;i < n;i++)
:这行代码开始一个 for 循环,循环变量 i 的初始值为 1,循环条件为 i < n。sum *= i;
:这行代码将变量 sum 与变量 i 相乘,并将结果赋值给 sum。printf("%d",sum);
:这行代码使用 printf 函数打印变量 sum 的值。return 0;
:在 main 函数的结尾,使用 return 语句将返回值设为 0。- 在
for
循环中,变量 i 的初始值为 1,每次循环 i 的值递增 1,直到达到 n 的值。因此,for 循环的执行次数为 n - 1。在循环中,执行了一次乘法操作 sum *= i,共执行了 n - 1 次。
- 故而程序的执行次数为: T ( N ) = 5 + 2 ∗ ( N − 1 ) = 2 N + 3 , T(N)=5+2*(N-1)=2N+3, T(N)=5+2∗(N−1)=2N+3, lim N → ∞ T ( N ) = O ( N ) \lim\limits_{N\rarr\infin}T(N)=O(N) N→∞limT(N)=O(N)。
1.2.3 对数时间复杂度( O ( l o g N ) O(log N) O(logN))
#include <stdio.h>void logarithmicAlgorithm(int n) {int i = 1;while (i < n) {printf("%d\n", i);i *= 2; // 对数时间复杂度的关键步骤}
}int main() {int n = 16;logarithmicAlgorithm(n);return 0;
}
这段代码的执行过程如下:
- 在
main
函数中,声明一个整数变量 n 并赋值为 16。- 调用
logarithmicAlgorithm()
函数,并将变量 n 作为参数传递给该函数。- 进入
logarithmicAlgorithm
函数。- 在
logarithmicAlgorithm
函数中,声明一个整数变量 i 并赋值为 1。- 进入
while
循环,检查条件 i < n 是否满足。由于此时 i 的初始值为 1,且 1 小于 16,条件成立,进入循环体。- 在循环体内,使用
printf
函数打印变量 i 的值。- 执行
i *= 2
,将 i 的值乘以 2。- 回到循环的开头,再次检查条件 i < n。如果条件仍然成立,继续执行循环体;如果条件不成立,跳出循环。
- 当 i 的值达到或超过 n(即 16)时,条件 i < n 不再满足,跳出循环。
- 退出
logarithmicAlgorithm
函数。- 回到
main
函数,继续执行后续的代码。执行return 0;
语句,结束程序。
- 设
while
循环的判断执行次数为x, 2 = N , ⇒ 2 x − 1 = l o g 2 N + 1 2 = N,\rArr 2^{x-1} = log_2N+1 2=N,⇒2x−1=log2N+1
while循环内的执行次数为 2 ∗ l o g 2 N 2*log_2N 2∗log2N
- 故而程序的执行次数为: T ( N ) = 7 + 3 ∗ l o g 2 N , T(N)= 7+3 * log_2N, T(N)=7+3∗log2N, lim N → ∞ T ( N ) = O ( l o g N ) \lim\limits_{N\rarr\infin}T(N)=O(logN) N→∞limT(N)=O(logN)。
1.2.4 平方时间复杂度( O ( N 2 ) O(N^2) O(N2)
#include <stdio.h>void quadraticAlgorithm(int n) {for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {printf("(%d, %d)\n", i, j);}}
}int main() {int n = 3;quadraticAlgorithm(n);return 0;
}
这段代码的执行过程如下:
- 在
main
函数中声明一个整数变量n,并赋值为3。- 调用
quadraticAlgorithm()
函数,并把变量n作为形参传递给函数。- 进入函数
quadraticAlgorithm()
。- 外部
for
循环的判断执行次数为n+1,外部循环循环一次内部for
循环判断的执行次数为n+1,printf
语句的执行次数为n。故而外部
for
循环的执行次数就为n+1,内部for
循环的总执行次数就为n*(n+1),内部for
循环的printf
语句的总执行次数为 n 2 n^2 n2
- 退出函数
quadraticAlgorithm()
。- 继续执行
main
函数中的return 0;
语句,结束程序。
- 故程序的执行次数为: T ( N ) = 1 + 1 + 1 + ( N + 1 ) + N ∗ ( N + 1 ) + N ∗ N + 1 + 1 = 2 N 2 + 2 N + 6 , T(N) =1+1+1+(N+1)+N*(N+1)+N*N+1+1=2N^2+2N+6, T(N)=1+1+1+(N+1)+N∗(N+1)+N∗N+1+1=2N2+2N+6, lim N → ∞ T ( N ) = O ( N 2 ) \lim\limits_{N\rarr\infin}T(N)=O(N^2) N→∞limT(N)=O(N2)
1.3 常见的函数的时间复杂度
以下图片整理了一些常用的时间复杂度类。表中, p o l y ( x ) = x O ( 1 ) poly(x) = xO(1) poly(x)=xO(1),也就是 x 的多项式。也可以访问网页版点击此处跳转
二、空间复杂度
2.1 空间复杂度的定义
在计算机科学中,一个算法或程序的空间复杂度定性地描述该算法或程序运行所需要的存储空间大小。空间复杂度是相应计算问题的输入值的长度的函数,它表示一个算法完全执行所需要的存储空间大小。和时间复杂度类似,空间复杂度通常也使用大O记号来渐进地表示。例如: O ( n ) 、 O ( n α ) 、 O ( n ∗ l o g n ) 、 O ( 2 n ) O(n)、{\displaystyle O(n^{\alpha })}、O(n*logn)、O(2^n) O(n)、O(nα)、O(n∗logn)、O(2n)。
空间复杂度用于评估算法在执行过程中所需的额外空间或内存的量级或增长趋势。它主要关注算法在运行过程中所使用的额外存储空间,包括算法使用的数据结构、临时变量、递归调用等。
- 注意:空间复杂度不计算空间,只计算变量的个数
常见的空间复杂度包括:
- 常数空间复杂度 ( O ( 1 ) ) (O(1)) (O(1)):算法使用固定的额外空间,不随输入的增加而变化。
- 线性空间复杂度 ( O ( n ) ) (O(n)) (O(n)):算法使用的额外空间与输入规模成线性关系。
- 平方空间复杂度 ( O ( n 2 ) ) (O(n^2)) (O(n2)):算法使用的额外空间与输入规模成平方关系。
- 对数空间复杂度 ( O ( l o g n ) ) (O(logn)) (O(logn)):算法使用的额外空间与输入规模成对数关系。
2.2 常见的空间复杂度的计算
- 就是去算变量和函数调用开辟的栈帧的个数之和
2.2.1 常数空间复杂度 ( O ( 1 ) ) (O(1)) (O(1))
void printHello() {printf("Hello, world!\n");
}
- 函数调用一次,开辟一个栈帧,空间复杂度为 O ( 1 ) O(1) O(1)。
2.2.2 线性空间复杂度 ( O ( n ) ) (O(n)) (O(n))
void printNumbers(int n) {int *arr =(int*)malloc(n * sizeof(int));// 执行其他操作...free(arr);
}
- 开辟了一个动态数组,变量的个数与 n n n成正比,取极限,和时间复杂度一样,常数可以忽略,空间复杂度为 O ( n ) O(n) O(n)。
2.2.3 平方空间复杂度 ( O ( n 2 ) ) (O(n^2)) (O(n2))
void printPairs(int n) {int **matrix = (int**)malloc(n * sizeof(int *));for (int i = 0; i < n; i++) {matrix[i] = (int*)malloc(n * sizeof(int));}// 执行其他操作...for (int i = 0; i < n; i++) {free(matrix[i]);}free(matrix);
}
- 开辟了一个二维的动态数组,变量的个数与 n 2 n^2 n2成正比,取极限,忽略常数,空间复杂度为 O ( n 2 ) O(n^2) O(n2)。
2.2.4 对数空间复杂度 ( O ( l o g n ) ) (O(logn)) (O(logn))
// 递归二分查找函数
int binarySearch(int arr[], int low, int high, int target) {if (low <= high) {int mid = low + (high - low) / 2;if (arr[mid] == target) {return mid;} else if (arr[mid] < target) {return binarySearch(arr, mid + 1, high, target);} else {return binarySearch(arr, low, mid - 1, target);}}return -1; // 如果找不到目标元素,返回-1
}
数组是提前排好序的递增数组,假设同时存在的栈帧最多为x个,因为只有找不到或者找到了
target
函数才会返回,此时区间长度要么是1,要么没找到不构成区间了,函数调用产生的栈帧才会开始销毁,有 2 x = n → x = l o g 2 n 2^x=n\to x=log_2n 2x=n→x=log2n,也就是最多开辟了 l o g 2 n log_2n log2n个栈帧。
- 故取极限,空间复杂度 T ( N ) 为 T(N)为 T(N)为 lim N → ∞ T ( N ) = O ( l o g N ) \lim\limits_{N\rarr\infin}T(N)=O(logN) N→∞limT(N)=O(logN)。
相关文章:

【数据结构与算法篇】之时间复杂度与空间复杂度
【数据结构与算法篇】之时间复杂度与空间复杂度 一、时间复杂度1.1时间复杂度的定义1.2 常见的时间复杂度的计算1.2.1 常数时间复杂度( O ( 1 ) ) O(1)) O(1))1.2.2 线性时间复杂度( O ( N ) O(N) O(N))1.2.3 对数时间复杂度( O (…...

硬件性能 - 网络瓶颈分析
简介 本文章主要通过Linux命令查看网络信息、判断是否出现网络瓶颈等简单分析方法。其他硬件性能分析如下: 1. 硬件性能 - CPU瓶颈分析 2. 硬件性能 - 掌握内存知识 3. 硬件性能 - 磁盘瓶颈分析 目录 1. 监控命令 sar 2. 带宽利用率 3. 网络延迟 4. 网络连接数 …...

stm32驱动MCP2515芯片,项目已通过测试
最近公司做一个项目,需要3路can通道,但是stm32看了很久,最多也就只有2个can,所以找到了一款MCP2515芯片,可以用spi驱动can。 已经实现了can的发送和接收,接收采用的是外部中断接收的方式。和单片机本身带的…...

Nginx部署前后端分离项目
dev.env.js解释 //此文件时开发环境配置文件 use strice//使用严格模式 const merge require(webpacl-merge)//合并对象 const prodEnv require(./prod.env)//导出 module.exports merge(prodEnv,{//合并两个配置文件对象并生成一个新的配置文件,如果合并的过程…...

pytorch多分类问题 CrossEntropyLoss()函数的输入size/shape不一致问题
在使用pytorch实现一个多分类任务的时候,许多多分类任务在训练过程中都会有如下的代码: criterion nn.CrossEntropyLoss() loss criterion(output, target) # output.size : [batch_size, class_num] # target.size : [batch_size]许多的初学者会卡在…...

硬盘或者U盘提示需要格式化的解决办法
插入硬盘之后提示: 使用驱动器 G:中的光盘之前需要将其格式化 是否要将其格式化? 如下图所示 顿时慌了啊,里面还有比较重要的东西呢,这一下子完蛋? 遇事找某宝,上面估计有这种技术服务。果然有这一类的技术服务&…...

Clip-Path
前言 借助clip-path,我们可以实现一些复杂的animation动画效果,我们先来简单概述一下它的特性,如MDN所描述的。 The clip-path CSS property creates a clipping region that sets what part of an element should be shown. Parts that are inside the region are shown, whi…...

Matlab绘图系列教程-Matlab 34 种绘图函数示例(下)
Matlab绘图系列教程:揭秘高质量科学图表的绘制与优化 文章目录 Matlab绘图系列教程:揭秘高质量科学图表的绘制与优化第一部分:入门指南1.1 简介关于本教程的目的与范围Matlab绘图在科学研究中的重要性 1.2 准备工作安装Matlab及其工具箱 1.3 …...

【Vue+Django】Training Management Platform Axios并发请求 - 20230703
需求陈述 由于API是特定单位/特定类别/特定教学方式的数据,故汇总数据需要循环请求不同单位/不同类别/不同教学方式。 技术要点 1.axios并发请求 2.JS for循环 3.Vue数组中出现 ob :Observer无法取值问题的解决方法 4.将数据转化为数组 5.一次请求所有数据后&…...

smart Spring:自定义注解、拦截器的使用(更新中...)
文章目录 〇、使用自定义注解的好处和工作原理一、如何使用自定义注解1.自定义一个注解2.在类、属性、方法上进行使用3.元注解 二、使用拦截器的好处和工作原理三、如何使用拦截器参考 本博客源码: 〇、使用自定义注解的好处和工作原理 自定义注解是Java语言提供的…...

php导出pdf
插件官网:TCPDF 博主用的是tp6框架 、tcpdf插件 composer require tecnickcom/tcpdf --ignore-platform-reqs 后面是忽略平台要求的参数 ---------------中文乱码start------------------ 关于中文乱码问题: 网上说的下载字体放入fonts 利用tools…...

【ECMAScript6_2】字符串
1、字符的Unicode表示法 ES6 加强了对 Unicode 的支持,允许采用\uxxxx形式表示一个字符,其中xxxx表示字符的 Unicode 码点。(\u0000-\uFFFF) 码点超过取值范围之后不能正确解读,但是只要给码点加上{}就可以正确解读。 …...

37.RocketMQ之Broker消息存储源码分析
highlight: arduino-light 消息存储文件 rocketMQ的消息持久化在我们在搭建集群时都特意指定的文件存储路径,进入指定的store目录下就可以看到。 下面介绍各文件含义 CommitLog 存储消息的元数据。produce发出的所有消息都会顺序存入到CommitLog文件当中。 CommitLog由多个文件…...

RabbitMq应用延时消息
一.建立绑定关系 package com.lx.mq.bind;import com.lx.constant.MonitorEventConst; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.*; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annota…...

【WEB自动化测试】- 浏览器操作方法
一、常用方法 1. maximize_window() 最大化窗口 (重点) 说明:如果能够在打开页面时,全屏显示页面,就能尽最大可能加载更多的页面,提高可定位性 2. set_window_size(width, height) 设置浏览器窗口的大小 (了解) 场景࿱…...

VSCode设置鼠标滚轮滑动设置字体大小
1:打开"文件->首选项->设置 2 :打开settings.json文件 英文版这里有个坑 一般点击我下图右上角那个{ } 就可以打开了 在 设置的json 文件中加入如下 “editor.mouseWheelZoom”: true { “editor.mouseWheelZoom”: true, “json.schemas”: [ ]}...

Spring MVC是什么?详解它的组件、请求流程及注解
作者:Insist-- 个人主页:insist--个人主页 作者会持续更新网络知识和python基础知识,期待你的关注 前言 本文将讲解Spring MVC是什么,它的优缺点与九大组件,以及它的请求流程与常用的注解。 目录 一、Spring MVC是什…...

基于Spring Boot的广告公司业务管理平台设计与实现(Java+spring boot+MySQL)
获取源码或者论文请私信博主 演示视频: 基于Spring Boot的广告公司业务管理平台设计与实现(Javaspring bootMySQL) 使用技术: 前端:html css javascript jQuery ajax thymeleaf 后端:Java springboot框架 …...

docker 基本命令安装流程
docker 基本命令安装流程 1.更新Ubuntu的apt源索引 $ sudo apt-get update2.安装包允许apt通过HTTPS使用仓库 $ sudo dpkg --configure -a $ sudo apt-get install apt-transport-https ca-certificates curl software-properties-common3.添加Docker官方GPG key $ curl -f…...

尚硅谷大数据Flink1.17实战教程-笔记02【Flink部署】
尚硅谷大数据技术-教程-学习路线-笔记汇总表【课程资料下载】视频地址:尚硅谷大数据Flink1.17实战教程从入门到精通_哔哩哔哩_bilibili 尚硅谷大数据Flink1.17实战教程-笔记01【Flink概述、Flink快速上手】尚硅谷大数据Flink1.17实战教程-笔记02【Flink部署】尚硅谷…...

【LeetCode每日一题合集】2023.7.3-2023.7.9
文章目录 2023.7.3——445. 两数相加 II(大数相加/高精度加法)2023.7.4——2679. 矩阵中的和2023.7.5——2600. K 件物品的最大和(贪心)代码1——贪心模拟代码2——Java一行 2023.7.6——2178. 拆分成最多数目的正偶数之和&#x…...

java企业工程项目管理系统平台源码
工程项目管理软件(工程项目管理系统)对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营,全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#…...

软件设计模式与体系结构-设计模式-行为型软件设计模式-访问者模式
目录 二、访问者模式概念代码类图实例一:名牌运动鞋专卖店销售软件实例二:计算机部件销售软优缺点适用场合课程作业 二、访问者模式 概念 对于系统中的某些对象,它们存储在同一个集合中,具有不同的类型对于该集合中的对象&#…...

【LeetCode】503. 下一个更大元素 II
503. 下一个更大元素 II(中等) 方法:单调栈 「 对于找最近一个比当前值大/小」的问题,都可以使用单调栈来解决。栈可以很好的保存原始位置,最近影射栈顶。题目要求更大,因此更大即解–出栈,更小…...

使用infura创建以太坊网络
创建账号 https://www.infura.io/zh 进入控制台Dashboard,选择CREATE API KEY 创建成功后,进入API KEY查看,使用PostMan测试 返回result即为当前区块。...

TCP/IP协议是什么?
78. TCP/IP协议是什么? TCP/IP协议是一组用于互联网通信的网络协议,它定义了数据在网络中的传输方式和规则。作为前端工程师,了解TCP/IP协议对于理解网络通信原理和调试网络问题非常重要。本篇文章将介绍TCP/IP协议的概念、主要组成部分和工…...

python图像处理实战(三)—图像几何变换
🚀写在前面🚀 🖊个人主页:https://blog.csdn.net/m0_52051577?typeblog 🎁欢迎各位大佬支持点赞收藏,三连必回!! 🔈本人新开系列专栏—python图像处理 ❀愿每一个骤雨初…...
学习vue2笔记
学习vue2笔记 文章目录 学习vue2笔记脚手架文件结构关于不同版本的Vuevue.config.js配置文件ref属性props配置项mixin(混入)插件scoped样式总结TodoList案例webStorage组件的自定义事件全局事件总线(GlobalEventBus)消息订阅与发布(pubsub&am…...

【SQL】查找多个表中相同的字段
--查找字段所在 SELECTbb.TABLE_NAME,bb.COLUMN_NAME ,aa.COLUMN_ID,aa.DATA_TYPE,aa.DATA_LENGTH ,bb.COMMENTS FROMuser_tab_cols aa JOIN user_col_comments bb ONaa.TABLE_NAME bb.TABLE_NAMEAND aa.COLUMN_NAME bb.COLUMN_NAME JOIN dba_objects cc ONbb.TABLE_NAME cc…...

“未来之光:揭秘创新科技下的挂灯魅力“
写在前面: 高度信息化当下时代,对电脑及数字设备的需求与日俱增无处不在,随之而来的视觉疲劳和眼睛问题也攀升到了前所未有的高度。传统台灯对于长时间使用电脑的人群来说是完全无法解决这些问题的。一款ScreenBar Halo 屏幕挂灯,…...