算法空间复杂度计算
目录
空间复杂度定义
影响空间复杂度的因素
算法在运行过程中临时占用的存储空间讲解
例子
斐波那契数列递归算法的性能分析
二分法(递归实现)的性能分析
空间复杂度定义
空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大小的量度。
一个算法在计算机存储器上所占用的存储空间,包括程序代码所占用的空间,输入数据所占用的空间和辅助变量所占用的空间这三个方面。
影响空间复杂度的因素
注意:
一个算法的空间复杂度只考虑在运行过程中为局部变量分配的存储空间的大小,它包括为参数表中形参变量分配的存储空间和为在函数体中定义的局部变量分配的存储空间两个部分。若一个算法为递归算法,其空间复杂度为递归所使用的堆栈空间的大小。它等于一次调用所分配的临时存储空间的大小乘以被调用的次数(即为递归调用的次数加1,这个1表示开始进行的一次非递归调用)
递归的空间复杂度: 每次递归所开空间*深度。
算法在运行过程中临时占用的存储空间讲解
1、有的算法只需要占用少量的临时工作单元,而且不随问题规模的大小而改变,我们称这种算法是“就地”进行的,是节省存储的算法,下面会介绍。
2、有的算法需要占用的临时工作单元数与解决问题的规模n有关,它随着n的增大而增大,当n较大时,将占用较多的存储单元,例如快速排序和归并排序算法就属于这种情况。
计算方法
①忽略常数,用O(1)表示
②递归算法的空间复杂度=递归深度n*每次递归所要的辅助空间
③对于单线程来说,递归有运行时堆栈,求的是递归最深的那一次压栈所耗费的空间的个数,因为递归最深的那一次所耗费的空间足以容纳它所有递归过程。
为什么要求递归的深度呢?
因为每次递归所需的空间都被压到调用栈里(这是内存管理里面的数据结构,和算法里的栈原理是一样的),一次递归结束,这个栈就是就是把本次递归的数据弹出去。所以这个栈最大的长度就是递归的深度。
例子
1、空间算法的常数阶
如上图,这里有三个局部变量分配了存储空间,所以f(n) = 1 + 1 + 1 = 3,根据上面的法则该函数不受n的影响且为常数项,所以空间复杂度记作O(1)。这种与问题的大小无关(n的多少),执行时间恒定的算法,我们称之为具有O(1)的空间复杂度,又叫常数阶。
2、两个函数,空间复杂度分别为:
# O(1)
def f1(n):j = 0for i in range(n):j += 1return j# O(n)
def f2(n):a = []for i in range(n):a.append(i)return a
在第一个函数中,所需开辟的内存空间并不会随着n的变化而变化,即此算法空间复杂度为一个常量,所以表示为O(1)。在第二个函数中,随着n的增大,开辟的内存大小呈线性增长,这样的算法空间复杂度为O(n)。在递归的时候,会出现空间复杂度为logn的情况,比较特殊。
3、空间算法的线性阶(递归算法)
如上图,这是一个递归算法(计算从n + (n-1) + (n-2) + … + 2 + 1的和)
每当执行一次该函数就会为tmp分配一个临时存储空间,所以f(n) = 1*(n-1+1) = n,函数是受n影响的所以空间复杂度记为O(n)
斐波那契数列递归算法的性能分析
斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……
这个数列从第3项开始,每一项都等于前两项之和。
如果设F(n)为该数列的第n项(n∈N*),那么这句话可以写成如下形式::F(n)=F(n-1)+F(n-2)
显然这是一个线性的递推数列。
通项公式 :
上面就是斐波那契数列的递推公式,这样一个完全是自然数的数列,通项公式却是用无理数来表达的。而且当n趋向于无穷大时,前一项与后一项的比值越来越逼近黄金分割0.618
递推是公式是求解斐波那契数列的一个方法,我们当然也可以用计算机编写程序来求解。
方法一(迭代法)
/// <summary>/// 斐波那契(迭代法)/// </summary>/// <param name="n"></param>/// <returns></returns>int Fibonacci(int n){if (n <= 0)return -1;if (n == 1 || n == 2)return 1;else{int num = 0;int a = 1;int b = 1;while (n - 2 > 0){num = a + b;a = b;b = num;n--;}return num;}}
时间复杂度:
while以外的算法语句都忽略不计(不随n的变化而变化)
while算法语句所有语句
f(n) = 4 *(n - 2) = 4n - 8
时间复杂度记为:O(n)
空间复杂度:
算法中num、a、b只创建1次
s(n) = 1 + 1 + 1 = 3
空间复杂度记为:O(1)
方法二(递归法)
def fibonacci(n):if n <= 0:return 0elif n == 1:return 1else:return fibonacci(n - 1) + fibonacci(n - 2)
首先回顾一下时间复杂度:递归算法的时间复杂度 = 递归的次数 * 每次递归中的操作次数。每次递归进行了一次加法操作,时间复杂度是O(1),递归的次数可以抽象成一棵递归树:(以n=5为例)
在这棵二叉树中每一个节点都是一次递归,一棵深度(按根节点深度为1)为k的二叉树最多可以有 个节点,所以该递归算法的时间复杂度为O(2^n),这个复杂度是非常大的,随着n的增大,耗时是指数上升的。
然后再来看空间复杂度:递归算法的空间复杂度 = 每次递归的空间复杂度 * 递归深度。
为什么要求递归的深度呢?因为每次递归所需的空间都被压到调用栈里(这是内存管理里面的数据结构,和算法里的栈原理是一样的),一次递归结束,这个栈就是把本次递归的数据弹出去。所以这个栈最大的长度就是递归的深度。
回到斐波那契数列的例子,每次递归所需要的空间大小都是一样的,所以每次递归中需要的空间是一个常量,并不会随着n的变化而变化,每次递归的空间复杂度就是 O(1)。递归的深度如图所示:
递归第n个斐波那契数的话,递归调用栈的深度就是n。那么每次递归的空间复杂度是O(1), 调用栈深度为n,所以这段递归代码的空间复杂度就是O(n)。
此算法时间复杂度非常高的主要原因是最后一行的两次递归,所以优化算法的方向就是减少递归的调用次数:
def fibonacci(first, second, n): #初始值 first = second = 1if n <= 0:return 0elif n <= 2:return 1elif n == 3:return first + secondelse:return fibonacci(second, first + second, n - 1)
举例来说 n=5 时 fibonacci(1,1,5) → fibonacci(1,2,4) → fibonacci(2,3,3) → 2+3=5。这里相当于用first和second来记录当前相加的两个数值,此时就不用两次递归了。因为每次递归的时候n减1,即只是递归了n次,所以时间复杂度是 O(n)。同理递归的深度是n-2,每次递归所需的空间还是常数,所以空间复杂度依然是O(n)。
最后总结一下:
可以看出,求斐波那契数的时候,使用递归算法并不一定在性能上是最优的,但递归确实简化了代码层面的复杂度。
二分法(递归实现)的性能分析
方法一(迭代法)
/// <summary>/// 二分查找/// </summary>/// <param name="arr">查找数组</param>/// <param name="len">数组长度</param>/// <param name="num">查找项</param>/// <returns></returns>int BinarySearch(int[] arr,int len,int num){int left = 0;int right = len - 1;int mid;while (left <= right){mid = (left + right) / 2;if (arr[mid] > num)right = mid - 1;else if (arr[mid] < num)left = mid + 1;elsereturn mid;}return -1;}
时间复杂度:
left、right、mid运算次数
f(n1) = 1 + 1 + 1 = 3
我们将While循环中的运算作为一个整体看待,每次都是折半运算次数
f(n2) = log2^n
总运行次数
f(all) = f(n1)+f(n2) = 3 + log2 ^ n
时间复杂度记为:O(log2^n)
空间复杂度:
算法中left、right、mid只创建的次数
s(n) = 1 + 1 + 1 = 3
空间复杂度记为:O(1)
方法二(递归法)
def binary_search(arr, l, r, x):if r >= l:mid = l + (r - l) // 2if arr[mid] == x:return midelif arr[mid] > x:return binary_search(arr, l, mid - 1, x)else:return binary_search(arr, mid + 1, r, x)else:return -1
此算法时间复杂度为O(logn)。每次递归的空间复杂度主要就是参数里传入的这个arr数组,但需要注意的是在C/C++中函数传递数组参数,不是整个数组拷贝一份传入函数而是传入数组首元素地址。也就是说每一层递归都是公用一块数组地址空间的,所以每次递归的空间复杂度是常数即:O(1)。(Python呢?)再来看递归的深度,二分查找的递归深度是logn ,递归深度就是调用栈的长度,那么这段代码的空间复杂度为 1 * logn = O(logn)。
注意:关注语言在传递函数参数时,是拷贝整个数值还是拷贝地址,如果是拷贝整个数值那么该二分法的空间复杂度就是O(nlogn)。
相关文章:

算法空间复杂度计算
目录 空间复杂度定义 影响空间复杂度的因素 算法在运行过程中临时占用的存储空间讲解 例子 斐波那契数列递归算法的性能分析 二分法(递归实现)的性能分析 空间复杂度定义 空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大…...

C++ lambda函数个人理解
及方便自己在函数内部定义函数 int main() {int i 1;auto c [](int a, int c) {return ab;};int d a(2, i);cout<<c;return 0; }格式: auto functionname [capture](parameters) -> return_type { /* … */ }; (1)[capture] &a…...

SwiftUI的context Menu
SwiftUI的 context Menu 现在来演示一下如何使用 SwiftUI 的 Context Menu 。 代码: import SwiftUIstruct ContextMenuBootCamp: View {State var bgColor: Color .purplevar body: some View {VStack(alignment: .leading, spacing: 10.0) {Image(systemName: …...

【数据结构】树与堆 (向上/下调整算法和复杂度的分析、堆排序以及topk问题)
文章目录 1.树的概念1.1树的相关概念1.2树的表示 2.二叉树2.1概念2.2特殊二叉树2.3二叉树的存储 3.堆3.1堆的插入(向上调整)3.2堆的删除(向下调整)3.3堆的创建3.3.1使用向上调整3.3.2使用向下调整3.3.3两种建堆方式的比较 3.4堆排…...

安装CDH平台的服务器磁盘满了,磁盘清理过程记录
1.使用hdfs命令查看哪个文件占用最大 hdfs dfs -du -h /tmp 2.我的服务器上显示/tmp/hive/hive文件夹下的,一串字符串命名的文件特别大几乎把磁盘占满了 网上查到/tmp文件是临时文件,由于hiveserver2任务运行异常导致缓存未删除,正常情况下…...

《互联网的世界》第七讲-能源
本想聊聊 tcp 和 quic,但这些都属于术的范畴,变化多端,等孩子们长大了又不知变成什么样子了,趁这段时间在家,还是得讲一些相对不变的东西,或法或势。 从 安阳卖血糕的精巧篦子 想到如何做圆米粉和圆面条&a…...

前端代码整洁与规范之CSS篇
一、代码整洁 1. 命名规范 CSS 类名的命名应该简洁清晰,能够准确描述元素的作用。避免使用无意义的名称,例如“a”、“b”等,而应该使用有意义的英文单词或单词缩写。同时,也要避免使用驼峰命名法和下划线命名法混杂使用&#x…...

在【IntelliJ IDEA】中配置【Tomcat】【2023版】【中文】【图文详解】
作为一款功能强大的集成开发环境(IDE),IntelliJ IDEA为Web服务器提供了卓越的支持,从而极大地简化了程序员在Web开发过程中的工作流程。学习Java Web开发实质上就是掌握如何创造动态Web资源,这些资源在完成开发后&…...

【SSM】任务列表案例 基本CRUD SSM整合
文章目录 一、案例功能预览二、接口分析三、前端工程导入四、后端程序实现和测试4.1 准备4.2 功能实现4.2.1 分页查询显示4.2.2 添加计划4.2.2 删除计划4.2.3 修改计划 4.3 前后联调 一、案例功能预览 Github 地址 : ssm-integration-part 二、接口分析 学习计划…...

基于微信小程序的校园跑腿小程序,附源码
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...

网络学习:9个计算机的“网络层”知识点
目录 一、IP 地址 1.1 分类表示法: 1.1.1 分类表示地址的其他说明 1.2 无分类编址 CIDR 二、IP 数据报文格式 Q: IP 报文里有什么?可以不按顺序或者字节来讲一讲 三、 路由概念 3.1 路由表 3.2 路由网络匹配 3.3 ARP 解析 3.4 RARP 逆地址解析…...

web项目的搭建
使用Webstorm并创建Next.js文件 1、配置nodejs环境、安装webstorm【配置node.js可以使用nvm去管理nodejs的版本】 2、需要破解webstorm,可能会导致原本的idea失效,注册码过期 3、taobao的npm过期,导致npm is sass执行不成功,需…...

C++for语句
1.求平均年龄 班上有学生若干名,给出每名学生的年龄(整数),求班上所有学生的平均年龄,保留到小数点后两位 输入 第1行有一个整数n(1 <= n <=100),表示学生的人数;其后n行每行有1个整数,表示每个学生的年龄,取值为15~25 输出 一行,包含一个浮点数,为所求的平…...

最新基于R语言lavaan结构方程模型(SEM)技术
原文链接:最新基于R语言lavaan结构方程模型(SEM)技术https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247596681&idx4&sn08753dd4d3e7bc492d750c0f06bba1b2&chksmfa823b6ecdf5b278ca0b94213391b5a222d1776743609cd3d14…...

【网络安全】-数字证书
数字证书 数字证书是互联网通讯中用于标志通讯各方身份信息的一串数字或数据,它为网络应用提供了一种验证通信实体身份的方式。具体来说,数字证书是由权威的证书授权(CA)中心签发的,包含公开密钥拥有者信息以及公开密…...

【C++ 】stack 和 queue
1. 标准库中的stack stack 的介绍: 1. stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行 元素的插入与提取操作 2. stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其…...

html--彩虹马
文章目录 htmljscss 效果 html <!DOCTYPE html> <html lang"en" > <head> <meta charset"UTF-8"> <title>Rainbow Space Unicorn</title> <link rel"stylesheet" href"css/style.css"> &l…...

如何将应用一键部署至多个环境?丨Walrus教程
在 Walrus 平台上,运维团队在资源定义(Resource Definition)中声明提供的资源类型,通过设置匹配规则,将不同的资源部署模板应用到不同类型的环境、项目等。与此同时,研发人员无需关注底层具体实现方式&…...

Redis的一些问题,解决并发的
项目通布隆过滤器: 布隆过滤器: 布隆过滤器是一种空间效率非常高的数据结构,用于快速判断一个元素是否可能存在于一个集合中。它由一个位数组(通常是长度为 m 的比特数组)和 k 个不同的哈希函数组成。当一个元素被加入…...

郭炜老师mooc第十一章数据分析和展示(numpy,pandas, matplotlib)
多维数组库numpy numpy创建数组的常用函数 # numpy数组import numpy as np #以后numpy简写为np print(np.array([1,2,3])) #>>[1 2 3] print(np.arange(1,9,2)) #>>[1 3 5 7] 不包括9 print(np.linspace(1,10,4)) #>>[ 1. 4. 7. 10.] # linespace(x,y,n)&…...

Redis主从架构和管道Lua(一)
Redis主从架构 架构 Redis主从工作原理 如果为master配置了一个slave,不管这个slave是否是第一次连接上Master,它都会发送一个PSYNC命令给master请求复制数据。master受到PSYNC命令,会在后台进行数据持久化通过bgsave生成最新的 RDB快照文件,持久化期间…...

GTH手册学习注解
CPLL的动态配置 终于看到有这个复位功能了 QPLL SWITCHing需要复位 器件级RESET没发现有管脚引出来 两种复位方式,对应全复位和器件级复位 对应的复位功能管脚 改那个2分频的寄存器说明段,复位是自动发生的?说明可能起效了,但是分…...

html5cssjs代码 002 50以内的加法算式
html5&css&js代码 002 一些基本概念 50以内的加法算式 一、代码二、解释 50以内的加法算式。 一、代码 <!DOCTYPE html> <html lang"en"> <head><title>50以内的加法算式</title><meta charset"UTF-8"><m…...

[React 进阶系列] React Context 案例学习:使用 TS 及 HOC 封装 Context
[React 进阶系列] React Context 案例学习:使用 TS 及 HOC 封装 Context 具体 context 的实现在这里:[React 进阶系列] React Context 案例学习:子组件内更新父组件的状态。 根据项目经验是这样的,自从换了 TS 之后,…...

网络编程:网络编程基础
一、网络发展 1.TCP/IP两个协议阶段 TCP/IP协议已分成了两个不同的协议: 用来检测网络传输中差错的传输控制协议TCP 专门负责对不同网络进行2互联的互联网协议IP 2.网络体系结构 OSI体系口诀:物链网输会示用 2.1网络体系结构概念 每一层都有自己独…...

力扣热题100_矩阵_73_矩阵置零
文章目录 题目链接解题思路解题代码 题目链接 73.矩阵置零 给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1: 输入:matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&…...

C++程序设计-第四/五章 函数和类和对象【期末复习|考研复习】
前言 总结整理不易,希望大家点赞收藏。 给大家整理了一下C程序设计中的重点概念,以供大家期末复习和考研复习的时候使用。 C程序设计系列文章传送门: 第一章 面向对象基础 第四/五章 函数和类和对象 第六/七/八章 运算符重载/包含与继承/虚函…...
C#快速入门基础
本篇文章从最基础的C#编程开始学习,经过非常优秀的面向对象编程思想和方法的学习,为C#编程打下基础。 第 01 章 C#开发环境之VS使用和.NET平台基础 1.1 Visual Studio 开发环境 1.1.1 硬件环境 i5CPUi5CPU(建议 4核 4线程或以上 ࿰…...

UnityShader常用算法笔记(颜色叠加混合、RGB-HSV-HSL的转换、重映射、UV序列帧动画采样等,持续更新中)
一.颜色叠加混合 1.Blend混合 // 正常,透明度混合 Normal Blend SrcAlpha OneMinusSrcAlpha //柔和叠加 Soft Additive Blend OneMinusDstColor One //正片叠底 相乘 Multiply Blend DstColor Zero //两倍叠加 相加 2x Multiply Blend DstColor SrcColor //变暗…...

Vue3调用钉钉api,内嵌H5微应用单点登录对接
钉钉内嵌H5微应用单点登录对接 https://open.dingtalk.com/document/isvapp/obtain-the-userid-of-a-user-by-using-the-log-free 前端需要的代码 1、安装 dingtalk-jsapi npm install dingtalk-jsapi2、在所需页面引入 import * as dd from dingtalk-jsapi; // 引入钉钉a…...