【数据结构】详解空间复杂度

news2024/9/23 9:21:44

                                

Yan英杰的博客

                                                        悟已往之不谏 知来者之可追


目录

空间复杂度

​案例1:计算BubbleSort的空间复杂度?       

案例2:计算斐波那契额数列的前N项的空间复杂度

案例3:计算阶乘递归Fac的空间复杂度?

案例4:F1和F2两函数是否使用的同一块空间

案例5:计算该程序的空间复杂度

案例6:经典OJ(难度中等)


空间复杂度

        
        空间复杂度也是一个数学表达式,是对一个算法在运行过程中临时占用存储空间大小的量度
        空间复杂度计算规则基本跟实践复杂度类似,也使用大O渐进表示法
        
        注意:函数运行时所需要的栈空间(存储参数、局部变量、一些寄存器信息等)在编译期间已经确定好了,因此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定。

案例1:计算BubbleSort的空间复杂度?       

        
// 1.计算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;
	}
}
分析:
                        注: 空间复杂度本质是:计算因为程序导致额外开辟的空间个数
                        
                        此时,该程序额外开辟了,三个变量,end exchange i,又因为空间复杂度同样使用的是大O表达式,所以我们由此得出,空间复杂度为O(N)

提问:

                        当时我在计算该程序的空间复杂度,有个疑问,为什么不把数组算进去

                        这是因为,我们在计算之前,就已经开辟了数组的栈帧空间,开始前就给出了,所以不用在空间复杂度内加上数组的大小

案例2:计算斐波那契额数列的前N项的空间复杂度

//计算斐波那契额数列的前N项的空间复杂度

long long* Fibonacci(size_t n)
{
	if (n == 0)
		return NULL;

	long long* fibArray = (long long*)malloc((n + 1) * sizeof(long long));
	fibArray[0] = 0;
	fibArray[1] = 1;
	for (int i = 2; i <= n; ++i)
	{
		fibArray[i] = fibArray[i - 1] + fibArray[i - 2];
	}
	return fibArray;
}

        分析:

                我们当前的变量为0,但是我们要求第N项的空间复杂度,所以我们开辟了n+1块空间,用来计算前N项和的空间复杂度,O(N+1)为其空间复杂度,但是大O的渐进表示法,我们计算出斐波那契额数列前N项和的空间复杂度为O(N)

 案例3:计算阶乘递归Fac的空间复杂度?

//计算阶乘递归Fac的空间复杂度?
long long Fac(size_t N)
{
	if (N == 0)
		return 1;

	return Fac(N - 1) * N;
}
        分析:
                
                由于该程序为递归,导致因为程序我们需要不断的开辟新的栈帧空间(每次传参均需要开辟一块新的空间)维护,所以此程序的空间复杂度为O(N)
        提问:
                  为什么开辟栈帧空间后需要额外再开辟新的栈帧空间?
                
                  主要是因为,栈帧空间只有在函数结束后,才会销毁,而递归时,函数其实并未销毁,这也导致了其不断开辟新的栈帧空间,也因为该程序的空间复杂度为O(N)       
        
        图解:
       

案例4:F1和F2两函数是否使用的同一块空间

        
//F1和F2两函数是否使用的同一块空间
void F2()
{
	int b = 0;
	printf("%p\n",&b);
}
void F1()
{
	int a = 0;
	printf("%p\n",&a);
}

int main()
{
	F1();
	F2();
	return 0;
}

解析: 

        当调用F1函数时在Main函数低地址处进行压栈,当出了F1函数,函数销毁,同时它用过的栈帧空间返回到内存中,当我们再调用F2时,F2继续在Main函数低地址处压栈,所以他俩所维护的栈帧空间其实是同一块

图解:
        
        

 提问:

        那如何修改,才能使两个函数指向不同栈帧空间?

分析:

       当我们在F1中调用F2时,使得F1函数无法释放栈帧空间,F2就必须在F1低地址处压栈,此时他们两个维护的栈帧空间则不相同

图解:

案例5:计算该程序的空间复杂度

//计算该程序的空间复杂度
long long Fib(size_t N)
{
	if (N<3)
	{
		return 1;
	}
	return Fib(N-1) - Fib(N-2);
}
         解析:
        
                为了详解这道题,我们要先清楚其时间复杂度如何计算
                
                由此看出其时间复杂度为O(2^N)
                
                

         

               当我们弄懂其时间复杂度后,以该时间复杂度为原型,上面为什么要弄懂,函数维护的空间其实也是有原因的,当Fib(2)销毁后,调用Fib(1),我们可以由此看出,其实Fib(2)和Fib(1)维护的是同一块栈帧空间,销毁后再返回到上一次,再销毁,再调用其他函数,其实总共维护的栈帧空间为N块
        
     图解:
        
                

                

                注:时间一去不复返无法重复利用,但是空间用了之后归还,可以重复利用

        

案例6:经典OJ(难度中等)

          示例 1:

输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]

        示例 2:

        

输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释:
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]

        解析:
        
                我们可以对其进行翻转,前k项进行翻转,后N-k进行翻转,最后进行整体翻转
                

        图解:

        

            错误示范:

                        

void reverse(int* nums,int begin ,int end)
{
	while (begin < end)
	{
		int tmp = nums[begin];
		nums[begin] = nums[end];
		nums[end] = tmp;
		begin++;
		end--;
	}

}
void rotate(int* nums, int numsSize, int k)
{
	reverse(nums,0,numsSize-k-1);
	reverse(nums,numsSize-k,numsSize-1);
	reverse(nums, 0, numsSize - 1);
}

         错误原因:
                
                当数组的输入的个数,小于输入的数组大小,就会出现数组越界访问的问题,所以导致了报错
                

        解决办法:
                
void reverse(int* nums,int begin ,int end)
{
	while (begin < end)
	{
		int tmp = nums[begin];
		nums[begin] = nums[end];
		nums[end] = tmp;
		begin++;
		end--;
	}

}
void rotate(int* nums, int numsSize, int k)
{
	if (k > numsSize)
	{
		k %= numsSize;
	}
	reverse(nums,0,numsSize-k-1);
	reverse(nums,numsSize-k,numsSize-1);
	reverse(nums, 0, numsSize - 1);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/400840.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

git团队合作 - branch分支的使用、主分支合并、冲突处理方案

情景例子开发部3人&#xff0c;组长man&#xff0c; 组员devA&#xff0c;devB&#xff1b;1&#xff09;组长man负责代码合并、冲突处理、检查代码、合并代码到master主分支&#xff1b;2&#xff09;组员devA负责开发3&#xff09;组员devB负责开发git仓库主次分支安排1&…

windows下qt creator 配置编译环境gcc,g++,gdb,cmake

MSVC&#xff1a;即Microsoft Visual C Compiler&#xff0c;即微软自己的编译器 MinGW&#xff1a;我们都知道GNU在Linux下面鼎鼎大名的gcc/g&#xff0c;MinGW则是指Minimalist GNU for Windows的缩写 这里我们选择MinGW&#xff0c;至于Qt中&#xff0c;这两种模式的区别&…

Python入门自学进阶-Web框架——34、富文本编辑器KindEditor、爬虫初步

KindEditor是一个轻量级的富文本编辑器&#xff0c;应用于浏览器客户端。一、首先是下载&#xff1a;http://kindeditor.net/down.php&#xff0c;如下图下载后是解压缩后&#xff1a;红框选中的都可以删除到&#xff0c;这些主要是针对不同的语言编写的示例&#xff0c;因为我…

一文教会你如何简单使用Fegin进行远程服务调用

文章目录1、fegin的基本介绍2、fegin的基本使用步骤3、项目中的实际运用4、测试前言在分布式微服务中&#xff0c;少不了会进行不同服务之间的相互调用&#xff0c;比如A服务要调用B服务中的接口&#xff0c;如何简单方便的实现呢&#xff1f;fegin可以来帮助。 1、fegin的基本…

如何禁止删除或修改RAR压缩包里的文件?很多人不知道这个功能

你是否有过这样的需求&#xff1f;把文件压缩成RAR格式后&#xff0c;需要对压缩包里的文件进行保护&#xff0c;以防别人或者自己误删文件&#xff0c;或者不小心修改了文件内容。 有些小伙伴可能会给压缩包里的文件都设置上“限制编辑”&#xff0c;这虽然也能防止随意更改内…

Stable Diffusion 个人推荐的各种模型及设置参数、扩展应用等合集(不断更新中)

一、说明 | 表示或者 表示 以上 二、模型 适用风景、房子、车子等漫画类风格 模型的VAE不要用模型附带的&#xff0c;好像就是naifu的官方vae&#xff0c;很老了&#xff0c;用 vae-ft-mse-840000-ema-pruned.ckpt 或者是 kl-f8-anime2.ckpt&#xff1b; 嵌入模型要下载作者…

免费集装箱箱号识别API,人工智能企业CIMCAI集装箱识别检测人工智能平台全球4千企业用户,支持API集成二次开发人工智能企业

免费集装箱箱号识别API&#xff0c;人工智能企业CIMCAI集装箱识别检测人工智能平台全球4千企业用户&#xff0c;支持API集成二次开发。箱信息识别及铅封号识别功能免费&#xff0c;顶尖AI集装箱识别率99.98%&#xff0c;全球No.1集装箱人工智能企业CIMCAI打造。中国上海人工智能…

chrome如何查看和修改除了密码,付款方式,地址意外的自动填充表单内容

这种自动填写的内容似乎无法设置。 软件地址&#xff1a;https://sqlitebrowser.org/dl/ 去这里查看地址 https://chromium.googlesource.com/chromium/src//master/docs/user_data_dir.md 比如我是windows&#xff0c;则地址为&#xff1a;C:\Users\用户名\AppData\Local\Go…

【Java】SpringBoot中实现异步编程

前言 首先我们来看看在Spring中为什么要使用异步编程&#xff0c;它能解决什么问题&#xff1f; 什么是异步&#xff1f; 首先我们先来看看一个同步的用户注册例子&#xff0c;流程如下&#xff1a; 异步的方式如下&#xff1a; 在用户注册后将成功结果返回&#xff0c;…

java:UUID和雪花生成算法

目录 UUID生成不重复命名方法 在实际项目中的运用 UUID算法的缺点 什么是雪花算法&#xff1f; UUID生成不重复命名方法 我们在做项目的时候可能需要用到全局唯一ID的场景&#xff0c;这种时候为了防止ID冲突可以使用36位的UUID UUID可以自动生成唯一的id。是java.util中自…

面朝大海,春暖花开丨2023年Kaadas凯迪仕全国经销商大会成功召开

3月8日&#xff0c;We——2023年Kaadas凯迪仕全国经销商大会将在中国青岛星光岛会议中心隆重举行&#xff0c;盛会汇聚了超过1000名优秀合作伙伴&#xff0c;规模空前。Kaadas凯迪仕品牌创始人&集团总裁苏志勇先生、集团董事长苏祺云先生以及各高层领导均莅临现场。 大会伊…

万字长文:Stable Diffusion 保姆级教程

万字长文&#xff1a;Stable Diffusion 保姆级教程 2022年绝对是人工智能爆发的元年&#xff0c;前有 stability.ai 开源 Stable Diffusion 模型&#xff0c;后有 Open AI 发布 ChatGPT&#xff0c;二者都是里程碑式的节点事件&#xff0c;其重要性不亚于当年苹果发布iPhone&a…

蓝库云|告诉你传统产业该如何进行数字化转型

在后疫情时代下&#xff0c;企业该如何在面临生存危机的情形下&#xff0c;投入「数字化转型」、提升公司竞争力&#xff0c;已成为许多公司的当务之急&#xff0c;但到底什么是数字化转型呢&#xff1f;传统产业又如何着手进行数位转型&#xff1f; 数字化转型是什么&#xf…

Uipath Excel 自动化系列13-ForEachExcelSheet(遍历Sheet)

活动描述 ForEachExcelSheet(遍历Sheet)&#xff1a;遍历Excel中的工作表&#xff0c;可以对 Excel 工作簿中的每个工作表重复一个或多个活动,该活动需与Use Excel File 活动选择的 Excel 文件一起使用。 使用场景&#xff1a;当处理包含多张工作表的 Excel 文件&#xff0c;…

项目管理工具DHTMLX Gantt灯箱元素配置教程:如何验证

DHTMLX Gantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表。可满足项目管理应用程序的大部分开发需求&#xff0c;具备完善的甘特图图表库&#xff0c;功能强大&#xff0c;价格便宜&#xff0c;提供丰富而灵活的JavaScript API接口&#xff0c;与各种服务器端技术&am…

【FPGA】Verilog:时序电路设计 | 二进制计数器 | 计数器 | 分频器 | 时序约束

前言&#xff1a;本章内容主要是演示Vivado下利用Verilog语言进行电路设计、仿真、综合和下载 示例&#xff1a;计数器与分频器 ​​ 功能特性&#xff1a; 采用 Xilinx Artix-7 XC7A35T芯片 配置方式&#xff1a;USB-JTAG/SPI Flash 高达100MHz 的内部时钟速度 存储器&#…

做自媒体真的能赚到钱吗?真的能赚到几十万吗?

自媒体在当今社会已经成为一个热门话题&#xff0c;越来越多的人开始尝试做自媒体&#xff0c;希望能够通过自媒体赚到钱。但是&#xff0c;做自媒体真的能赚到钱吗&#xff1f;能赚到几十万吗&#xff1f;下面我们来一一解答。 首先&#xff0c;做自媒体确实可以赚到钱。随着互…

硬件语言 Verilog HDL 学习 day02 数据流建模,行为级建模,结构化建模

1.数据流建模 1.含义&#xff1a;在电路规校较小的清况下&#xff0c;由于包含的门数比较少&#xff0c;设计者可以逐个地引用逻辑门实例把它 们互相连接起来&#xff0c; 因此使用门级建换进行设计是很合适的。对于具有数字逻辑电路设计基本知识的用户来讲&#xff0c;门级建模…

Java性能调优杀手锏JMH

JMH简介 JMH(Java Microbenchmark Harness)由 OpenJDK/Oracle 里面那群开发了 Java编译器的大牛们所开发&#xff0c;是一个功能强大、灵活的工具&#xff0c;它可以用于检测和评估Java应用程序的性能&#xff0c;主要目的是测量Java应用程序的性能&#xff0c;尤其是在多线程…

SpringBoot 中的 Aop + 自定义注解(内含源代码)

SpringBoot 中的 Aop 自定义注解&#xff08;内含源代码&#xff09; 源代码下载链接地址&#xff1a;https://download.csdn.net/download/weixin_46411355/87553544 目录SpringBoot 中的 Aop 自定义注解&#xff08;内含源代码&#xff09;源代码下载链接地址&#xff1a;…