空间复杂度(超详解+例题)
全文目录
- 引言
- 空间复杂度
- 例题
- test1
- test2(冒泡排序)
- test3(求阶乘)
- test4(斐波那契数列)
- 总结
引言
在上一篇文章中,我们提到判断一个算法的好坏的标准是时间复杂度与空间复杂度。
时间复杂度的作用是衡量一个算法运行的快慢;而空间复杂度是衡量一个算法运行所需的额外的空间。在上一篇文章中,我们已经了解了计算时间复杂度的方法,以及如何使用大O阶表示法来表示时间复杂度的大概值。
戳我转到时间复杂度详解哦
在本篇文章中将详细介绍关于空间复杂度的相关内容:
空间复杂度
空间复杂度也是一个数学表达式,是对一个算法在运行过程中所额外占用的空间大小的量度。
在时间复杂度中,我们以算法中基本语句执行的次数作为算法的时间复杂度;
而空间复杂度中,我们以变量被创建的个数作为算法的空间复杂度(不论是什么类型的变量,都算做一个空间复杂度)。
需要注意的是:由于函数运行时需要的栈空间在编译期间已经确定好了,因此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定(参数等一些数据不必计算)。
我们在计算空间复杂度时,依旧采用大O阶表示法来确定其大概值。
转换大O阶表示的方式与时间复杂度相同:
1、用常数1表示算法中的所有加法常数;
2、在修改后的数学表达式中只保留最高项;
3、如果最高项存在且不是1,则去掉该最高项的系数。
但是,通常情况下,我们是不需要将精确的空间复杂度计算出来后再转换的。与时间复杂度相同,空间复杂度的大O阶表示法也分为例如对数级(log n)、正比例级(n)、次方级(n^2)、指数级(2^n)等:

但是对于空间复杂度而言,最常见的就是O(1)与O(n),其他量级就不是很常见。
例题
接下来就通过几个栗子来理解空间复杂度:
test1
int* rotate(int* nums, int numsSize, int k)
{int* ret = (int*)calloc(numsSize, sizeof(int));int i = 0;for (i = numsSize-k; i < numsSize ; i++){*ret++ = nums[i];}for (i = 0; i < numsSize - k; i++){*ret++ = nums[i];}return ret-numsSize;
}
在这段算法中,我们实现了将数组的后k个元素移动到数组的前面。
在计算这个算法的空间复杂度时,数组nums、整型numsSize与k均为参数,所以不计算空间复杂度。在实现元素的移动时,我们动态开辟了一块空间,这块动态空间由numsSize个整型,所以这个算法的空间复杂度就是O(n)。
不难发现,在算法中还创建了一个整型变量i,但是,这个常数就省略不计了。
test2(冒泡排序)
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;}
}
这段算法是经典的冒泡排序。
在段算法中,额外申请了三个整型变量end、exchange、i 。空间复杂度是常数,大O表示法中常数忽略后表示为O(1)。
test3(求阶乘)
long long Fac(size_t N)
{if (N == 0)return 1;return Fac(N - 1) * N;
}
此算法可以实现求N的阶乘。
在这个算法中,我们通过函数递归的方式,每次递归将N-1作为参数,返回Fac(N - 1) 与 N的乘积。
参数为0时,递归终止,开始返回值。
这里需要注意的是,函数在栈中开辟函数栈帧时是依次开辟的。当函数调用它本身时,会在栈中再开辟一块空间作为新的函数的栈帧。在每一块栈帧中,并没有创建额外的变量,所以我们可以认为每一块栈帧的空间复杂度是常数个。所以,有多少次递归,就会有多少个函数的栈帧。
我们可以画图来表示在这个算法中栈帧的开辟:

从参数为N递归到参数为0,共递归了N+1次。省略常数1,该算法的空间复杂度就是O(n)。
test4(斐波那契数列)
long long Fib(size_t N)
{if (N < 3)return 1;return Fib(N - 1) + Fib(N - 2);
}
此算法通过递归实现计算第n个斐波那契数。
在上一篇文章中,我们介绍了这个算法的时间复杂度的计算,结果是O(2^n)。通过计算时间复杂度,我们了解了这个算法的递归规律:

根据上一个例题,我们知道,在这种没有新建变量的递归中,每次递归的空间复杂度都可以看作常数。大概是递归了2^n次,那空间复杂度也是O(2^n)吗?
其实并不是,其实这个算法的空间复杂度是O(n)。
函数调用时会为函数开辟一块栈帧,当函数调用结束后,这块空间就会被还给操作系统。这块空间是可以重复利用的。比如在调用某函数结束后,再次调用相同的函数时,所用的空间与上次调用完的空间是相同的,这里举一个小栗子:
void Fun1()
{int i = 10;printf("%p\n", &i);
}
void Fun2()
{int j = 10;printf("%p\n", &j);
}
int main()
{Fun1();Fun2();return 0;
}

这段代码中,main函数调用了两个相同的函数Fun1与Fun2。在这两个函数中都创建了一个整型的变量。我们打印这两个变量的地址,发现它们是相等的。这就说明这两个函数所使用的是同一块空间。
再回到斐波那契数列。这个算法的递归并不是我们想象的一次递归同时开辟两个函数栈帧,而是先在一条线上递归到终止后返回一个值,释放此次递归的空间,再回到上一级的递归,然后再到终止后返回一个值,再释放此次的空间,然后再回到上一级递归,释放空间。最终,将所有的返回值汇到最初的函数中,得到最终的结果:

这张图示应该可以比较清楚地描述该算法的递归:
首先顺着第一条线递归,直到小于3时终止。到此,函数一共递归N-1次,空间复杂度为O(n)。返回1后,为Fib(2)开辟的栈帧被释放;下一步调用Fib(1),并为其开辟空间,这时开辟的空间与刚才Fib(2)的空间是同一块该函数的参数也小于3,递归终止,返回1,为Fib(1)开辟的栈帧被释放。此时,Fib(N-4)的返回值就可以被计算出来,即Fib(2)与Fib(1)的和(假设N-4-1的值为2),返回后,为Fib(N-4)开辟的空间也被释放;接下来为Fib(N-5)开辟栈帧,该空间与刚才释放的Fib(N-4)的函数栈帧是同一块空间…
依次类推,其实该算法开辟的空间就只有最开始第一条线递归时所开辟的空间,后面的递归开辟空间时使用的都是之前释放的空间。所以,该算法的空间复杂度就是O(n)。
通过这个斐波那契数列的递归算法,我们不难发现:
时间是一去不复返的,在运行基本语句时,势必要消耗时间;
而空间是可以重复利用的,我们在使用完一块空间后,该空间被释放后是可以再次利用的。
所以在许多的算法中,会使用空间换时间的思想,尽量先保证时间复杂度的减少。
总结
在本篇文章中,我们了解了空间复杂度的相关知识,以及能够计算算法的空间复杂度
到此,对于算法效率的判断的两个标准空间复杂度与时间复杂度都已经介绍完了
如果大家认为我对某一部分没有介绍清楚或者某一部分出了问题,欢迎大家在评论区提出
如果本文对你有帮助,希望一键三连哦
希望与大家共同进步哦
相关文章:
空间复杂度(超详解+例题)
全文目录引言空间复杂度例题test1test2(冒泡排序)test3(求阶乘)test4(斐波那契数列)总结引言 在上一篇文章中,我们提到判断一个算法的好坏的标准是时间复杂度与空间复杂度。 时间复杂度的作用…...
Document-Level event Extraction via human-like reading process 论文解读
Document-Level event Extraction via human-like reading process 论文:2202.03092v1.pdf (arxiv.org) 代码:无 期刊/会议:ICASSP 2022 摘要 文档级事件抽取(DEE)特别困难,因为它提出了两个挑战:论元分散和多事件。第一个挑战…...
H5盲盒抽奖系统源码
盲盒抽奖系统4.0,带推广二维码防洪炮灰功能和教程。 支持微信无限回调登录 标价就是源码价格,vuetp5框架编写,H5网页,前后端分离 此源码为正规开发,正版产品已申请软著。 开源无加密无授权,可以二开使用…...
低代码平台和无代码平台哪个更适合开发企业管理系统?
编者按:本文分析了开发企业管理系统所需要的平台特性,并根据这些特点和低代码无代码的优劣比较,得出低代码平台更适合开发企业管理系统。关键词:私有化部署,可视化设计,源码交付,数据集成&#…...
75岁彪马再发NFT 复活美洲狮IP
在“运动品牌Web3”的潮流里,彪马(PUMA)绝对算是发烧友级别。2月22日,这家德国服装品牌的新NFT又来了,总量10000个Super PUMA NFT中,将有4000个以0.15 ETH(约为255美元)价格正式公售…...
大学生成人插画培训机构盘点
成人插画培训机构哪个好,成人学插画如何选培训班?给大家梳理了国内较好的插画培训机构排名,各有优势和特色,供大家参考! 一:国内成人插画培训机构排名 1、轻微课(五颗星) 主打课程有…...
【算法基础】一维差分 + 二维差分
👦个人主页:Weraphael ✍🏻作者简介:目前正在学习c和算法 ✈️专栏:【C/C】算法 🐋 希望大家多多支持,咱一起进步!😁 如果文章有啥瑕疵 希望大佬指点一二 如果文章对你有…...
游戏服务器框架 技能buff篇
游戏服务器框架 技能buff篇 1.状态 state 全局API 用于定义各种状态检查 bool IsDead(){ // 死亡buff if (buff->id 10001){ return true; } return false; } bool IsInvincible(){ if (buff->id 20001 || buff->id 20002){…...
网友说socket通信讲的不彻底,原来这才是Socket
关于对 Socket 的认识,大致分为下面几个主题,Socket 是什么,Socket 是如何创建的,Socket 是如何连接并收发数据的,Socket 套接字的删除等。 Socket 是什么以及创建过程 一个数据包经由应用程序产生,进入到…...
Nginx第二讲
目录 二、Nginx02 2.1 keepalived和heartbeat介绍 2.1.1 两者的介绍 2.1.2 keepalived简介 2.1.3 VRRP协议与工作原理 2.1.4 Keepalvied的工作原理 2.2 安装环境及keepalived 2.3 启动与验证keepalived 2.4 keepalived测试 2.4.1 环境准备 2.4.2 配置keepalived 2.…...
redis(win版)
1. 前言1.1 什么是RedisRedis是一个基于内存的key-value结构数据库。Redis 是互联网技术领域使用最为广泛的存储中间件,它是「Remote Dictionary Service」的首字母缩写,也就是「远程字典服务」。基于内存存储,读写性能高适合存储热点数据&am…...
【Linux】编辑器——vim(最小集+指令集+自动化配置)
目录 1.vim最小集 1.1 vim的三种模式 1.2 vim的基本操作 2.vim指令集 2.1 命令模式指令集 移动光标 删除文字 复制 替换 撤销上一次操作 更改 跳至指定的行 2.2 底行模式指令集 列出行号 跳到文件中的某一行 查找字符 保存文件 多文件操作 3.如何配置vim 配…...
Centos7+Xshell+Jenkins堆装
windows系统崩坏,重装测试类工具,心情崩了 windows硬盘损坏前,运行应用具慢。。。。。。慢着慢着就走了 从前部署在本地的jenkins,python,gitblit等相关脚本都凉透了,所以这次把服务部署到Centos7上…...
Android system实战 — Android R(11) 进程保活白名单
Android system实战 — Android R 进程保活白名单0. 前言1. 具体实现1.1 准备工作1.2 源码实现1.2.1 源码1.2.2 diff文件0. 前言 最近在Android R上实现一些需求,进行记录一下,关于进程保活的基础知识可以参考Android system — 进程生命周期与ADJ&#…...
oracle表 分组,并查每组第一条
oracle主要用到的函数:OVER(PARTITION BY) mysql主要用到的函数:LIMIT (用到3个地方:分组列、组内排序列、表名) oracle: select t.* from ( select a.*, ROW_NUMBER() OVER (PARTITION BY 分组列 ORDER BY 组内排…...
Java代码弱点与修复之——DE: Dropped or ignored exception(无视或忽略异常)
弱点描述 Dropped or ignored exception(DE)指的是在代码中抛出的异常被捕获后被无视或忽略了,而不是被适当地处理。这种情况通常发生在程序员没有处理异常或处理异常时不小心忽略了异常的情况下。 Dropped or ignored exception会导致程序无法正常工作,因为异常会阻塞程…...
JavaEE简单示例——动态SQL之更新操作<set>元素
简单介绍: 在之前我们做的学生管理系统的时候,曾经有一个环节是修改学生的数据。我们在修改的时候是必须将student对象的三个属性全部填入信息,然后全部修改才可以,这样会造成一个问题就是在我们明明只需要修改一个属性的时候却要…...
【极海APM32替代笔记】低功耗模式配置及配置汇总
【极海APM32替代笔记】低功耗模式配置及配置汇总 文章总结:(后续更新以相关文章为准) 【STM32笔记】低功耗模式、WFI命令等进入不了休眠的可能原因(系统定时器SysTick一直产生中断) 【STM32笔记】HAL库低功耗模式配置…...
攻击者失手,自己杀死了僵尸网络 KmsdBot
此前,Akamai 的安全研究员披露了 KmsdBot 僵尸网络,该僵尸网络主要通过 SSH 爆破与弱口令进行传播。在对该僵尸网络的持续跟踪中,研究人员发现了一些有趣的事情。 C&C 控制 对恶意活动来说,最致命的就是夺取对 C&C 服务…...
东阿县高新技术企业认定条件和优惠政策 山东同邦科技分享
东阿县高新技术企业认定条件和优惠政策 山东同邦科技分享 高新技术企业 在《国家重点支持的高新技术领域》内,持续进行研究开发与技术成果转化,形成企业核心自主知识产权,并以此为基础开展经营活动,在中国境内(不包…...
OpenClaw智能书签:用nanobot自动归类收藏网页内容
OpenClaw智能书签:用nanobot自动归类收藏网页内容 1. 为什么需要智能书签 作为一个每天要浏览大量技术文档和行业资讯的开发者,我发现自己陷入了"收藏即学会"的陷阱。Chrome书签栏里堆满了未分类的链接,Notion数据库里散落着零碎…...
AI 模型推理框架性能分析与对比
AI模型推理框架性能分析与对比 随着人工智能技术的快速发展,AI模型推理框架成为支撑各类应用落地的核心工具。无论是计算机视觉、自然语言处理还是推荐系统,高效的推理框架直接影响模型的响应速度、资源占用和部署成本。本文将从多个维度对比主流AI推理…...
feishu2md:飞书文档批量下载与Markdown转换解决方案
feishu2md:飞书文档批量下载与Markdown转换解决方案 【免费下载链接】feishu2md 一键命令下载飞书文档为 Markdown 项目地址: https://gitcode.com/gh_mirrors/fe/feishu2md 在团队协作和知识管理场景中,飞书文档已成为许多组织的核心工具。然而&…...
Django REST framework的应用场景
目录一、鉴权开发框架介绍二、Django REST framework是什么三、如何实现认证、权限与限流功能四、Django REST framework的应用场景一、鉴权开发框架介绍 鉴权开发框架是一种用于实现身份验证和授权的软件开发工具。它可以帮助开发者快速构建安全、可靠的身份验证和授权系统&a…...
Monocle 3实战:5步搞定单细胞marker基因筛选与可视化(R语言版)
Monocle 3实战:5步搞定单细胞marker基因筛选与可视化(R语言版) 单细胞RNA测序技术正在重塑我们对复杂生物系统的理解。在这个数据爆炸的时代,如何从海量的单细胞数据中快速准确地识别关键marker基因,成为每个研究者必须…...
解锁AMD锐龙隐藏性能:SMUDebugTool深度调校实战指南
解锁AMD锐龙隐藏性能:SMUDebugTool深度调校实战指南 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: https://gitc…...
SmartBMS:革新性开源智能电池管理系统技术解析
SmartBMS:革新性开源智能电池管理系统技术解析 【免费下载链接】SmartBMS Open source Smart Battery Management System 项目地址: https://gitcode.com/gh_mirrors/smar/SmartBMS 破解锂电池管理行业痛点:从安全隐患到性能瓶颈 在新能源技术飞…...
Unity引擎开发过的VR大场景项目有哪些?用到的网络技术,资源处理及热更新方案有哪些
我梳理了Unity引擎开发的VR大场景代表性项目,并从网络技术、资源处理、热更新方案三个核心技术维度进行了详细分析。一、代表性VR大场景项目 1. 基于VR的数字孪生智慧城市平台 开发方:香港理工大学温州技术创新研究院技术特点:整合GIS地理信息…...
OpenClaw+Qwen3-32B科研助手:文献综述自动生成与参考文献整理
OpenClawQwen3-32B科研助手:文献综述自动生成与参考文献整理 1. 为什么需要AI科研助手? 作为一名计算机专业的研究生,我每天要处理大量文献。最痛苦的时刻莫过于导师突然说"下周组会做个文献综述",而我手头只有几十篇…...
别再瞎装了!用NVIDIA-SMI一键查CUDA版本,保姆级PyTorch 2.6.0安装避坑指南
深度学习环境搭建实战:从CUDA版本诊断到PyTorch 2.6.0完美安装 刚接触深度学习的新手最常遇到的"入门杀"问题,往往不是模型调参或代码编写,而是环境搭建这个看似简单的环节。我见过太多人在安装PyTorch时直接复制粘贴网上的pip命令…...
