数据结构——复杂度的详解(空间复杂度和时间复杂度)

news2024/11/27 2:41:12

1.程序算法效率

1.1什么是算法?

算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。

1.2衡量算法好坏的标准

这是一个通过函数递归算法实现斐波那契数列的代码

long long Fib(int N)
{
	if (N < 3)
		return 1;

	return Fib(N - 1) + Fib(N - 2);
}

你认为这样的算法是否好呢?让我们带着疑惑来阅读本篇文章,相信你读完后一定会对此算法有所理解,也希望你能有所收获。

当我们写完的算法代码被编译成指令后运行程序,这期间必定消耗了时间和空间(内存空间)。通常衡量一个算法的好坏是以时间维度和空间维度这两个标准来衡量的。也就是今天要介绍的主题算法的时间复杂度和空间复杂度。

2.时间复杂度

2.1什么是时间复杂度?

时间复杂度的定义:时间复杂度的定义:在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。一个算法执行所耗费的时间,从理论上说,是不能算出来的,只有你把你的程序放在机器上跑起来,才能知道。但是我们需要每个算法都上机测试吗?是可以都上机测试,但是这很麻烦,所以才有了时间复杂度这个分析方式。一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法的时间复杂度。

2.2时间复杂度的计算

// 请计算一下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;
}

![在这里插入图片描述](https://img-blog.csdnimg.cn/2d7def86d6d745359554cd93bcc102fb.png

当然在实际的算法时间复杂度的计算中,我们并不会去计算一个精确的执行次数,而是去计算一个大概的执行次数。使用的方法是大O的渐进表示法

2.3大O的渐进表示法

大O符号(Big O notation):是用于描述函数渐进行为的数学符号。

大O的渐进表示法的推导方法:
1、用常数1来表示常数次的算法执行次数。
2、通常只保留算法函数式的最高阶。
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。

使用大O的渐进表示法以后,Func1的时间复杂度为:O(N^2)。
在这里插入图片描述

通过上面的例子不难发现,大O的渐进表示法实际上是去除了一些对结果影响不大的一些项。

2.4算法时间复杂度的考虑情况

在算法世界里时间复杂度的考量都是以最坏情况来进行考虑的。

假设有一个查找算法用来查找数组中的某个数x,那么将会有以下几种情况:
1、最好情况:O(1),此时x位于数组的第一位。
2、平均情况: O(N/2) ,此时x位于数组的中间位置。
3、最坏情况: O(N),此时x位于数组的最后一位。
我们应该从那种情况来考虑算法的复杂度呢?即不是最好情况,因为这有些许的不切实际。也不是平均情况,因为这个不太符合我们程序员的预期阈值。在算法世界里时间复杂度的考量都是以最坏情况来进行考虑的。

2.5时间复杂度试题讲解

// 计算Func2的时间复杂度?
void Func2(int N)
{
 int count = 0;
 for (int k = 0; k < 2 * N ; ++ k)
 {
 ++count;
 }
 int M = 10;
 while (M--)
 {
 ++count;
 }
 printf("%d\n", count);
}

解析:从上往下阅读代码可知,第一趟for循环一个需要执行2n次,下面的while程序需要执行10次,printf语句执行1次。其实本题的时间复杂度为F(n) = 2n+10+1。采用大O的渐进法表示,即O(N)。

// 计算Func3的时间复杂度?
void Func3(int N, int M)
{
 int count = 0;
 for (int k = 0; k < M; ++ k)
 {
 ++count;
 }
 for (int k = 0; k < N ; ++ k)
 {
 ++count;
 }
 printf("%d\n", count);
}

解析:从上往下阅读代码可知,第一趟for循环执行M次,第二趟for循环执行了N次,printf语句执行1次。程序运行的次数为:F(n) = N*M+1次。大O的渐进表示法为:O(N+M)。

// 计算Func4的时间复杂度?
void Func4(int N)
{
 int count = 0;
 for (int k = 0; k < 100; ++ k)
 {
 ++count;
 }
 printf("%d\n", count);
}

解析:从上往下阅读代码可知,这里for循环执行100次,printf语句执行一次。一共执行101次。采用大O的渐进表示法为:O(1)。这里可能很多刚接触的读者不理解为什么不是O(101)而是O(1)。这是因为Func4的复杂度量级是常数阶,常数阶的大O的渐进法表示形式就是O(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;
 }
}

解析:从上往下阅读代码可知,上面代码是一个经典的冒泡排序算法,该算法最坏的情况是需要执行(n*n+1)/2次,它的时间复杂度为:O(N^2)。这里我用 ^符号来表示次方。

// 计算BinarySearch的时间复杂度?
int BinarySearch(int* a, int n, int x)
{
 assert(a);
 int begin = 0;
 int end = n-1;
 // [begin, end]:begin和end是左闭右闭区间,因此有=号
 while (begin <= end)
 {
 int mid = begin + ((end-begin)>>1);
 if (a[mid] < x)
 begin = mid+1;
 else if (a[mid] > x)
 end = mid-1;
 else
 return mid;
 }
 return -1;
}

在这里插入图片描述

解析:上述代码为一个经典的二分查找算法。每次查找都是会砍掉一半的可找范围。上图例为10个有序数的二分查找算法图。可以分析出10个有序数的二分查找算法最坏的情况是执行4次。当10亿个有序数进行二分查找仅需30次左右便可以找到该数。这是一个理论上很猛的算法就是前提条件要有序。所以该代码的时间复杂度是O(logN)。即log以2为底N的对数。这里是由于编辑器对于底数优化表示格式不支持,故对2进行了省略。

// 计算斐波那契递归Fib的时间复杂度?
long long Fib(size_t N)
{
 if(N < 3)
 return 1;
 
 return Fib(N-1) + Fib(N-2);
}

在这里插入图片描述

解析:通过上图可以看出其实fib函数递归的次数大概是2的n次方次数(2^n)次数。时间复杂度为O(2 ^ n)。

3空间复杂度

3.1什么是空间复杂度?

空间复杂度也是一个数学表达式,是对一个算法在运行过程中临时占用存储空间大小的量度 。

3.2空间复杂度计算

这里要说明一个概念,程序的空间复杂度并不是程序所占空间的大小,而是计算的是程序内开辟的空间(如变量的个数,函数的调用等等)。空间复杂度计算规则基本跟时间复杂度类似,也使用大O渐进表示法

注意:函数运行时所需要的栈空间(存储参数、局部变量、一些寄存器信息等)在编译期间已经确定好了,因此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定。

3.3空间复杂度试题

// 计算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。故空间复杂度O(1)。

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

在这里插入图片描述

在这里插入图片描述

解析:上图一所示,其实函数栈帧销毁后,并不代表销毁后还给操作系统的空间不可以二次利用。这里我想引入一个经典的名言,时间一去不复还,空间可以重复用。如上图二所示,当函数在递归时,会开辟新的栈帧。当n=3时,会开辟3次栈帧。故空间复杂度为:O(n)。

4.常见复杂度的对比

运行(开辟空间)次数大O的渐进表示法量级
250O(1)常数阶
3lognO(logn)对数阶
2n+666O(n)线性阶
5n^2+5O(N^2)平方阶
n^3*n ^2O(N^3)立方阶
2^5+2*n+55O(2^n)质数阶

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

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

相关文章

轻量级权限框架之-Sa-ToKen

轻量级的权限认证框架 Sa-Token 目前主要五大功能模块&#xff1a;登录认证、权限认证、单点登录、OAuth2.0、微服务鉴权 登录认证 —— 单端登录、多端登录、同端互斥登录、七天内免登录 权限认证 —— 权限认证、角色认证、会话二级认证 Session会话 —— 全端共享Session、…

Hadoop3 集群搭建

测试环境 信息内容主机版本centos7机器数量3台Hadoop版本3.3.4安装包解压路径/home/tools/hadoop/ hosts配置 主机ip地址对应主机host192.168.57.188node1192.168.57.189node2192.168.57.190node3 一. 前置环境准备 安装JDK1.8(Hadoop支持1.8)创建非root用户(这里用的myuser…

关于企业文档能力开放,你想知道的都在这里了

最近一个朋友向我请教关于企业文档能力开放的事&#xff0c;说了一大堆的问题&#xff0c;我是做技术的&#xff0c;有很多基础知识和理论要向同行学习&#xff0c;所以给他解答了一通&#xff0c;但是朋友觉得解释的没啥实际用处。。。其实这个能力对很多人来说可能都不太明白…

MYBatis-Plus常用注解@TableName、@TableId、@TableField、@TableLogic

1-1&#xff1a;TableName 注解作用&#xff1a;设置实体类对应的表明 value作用&#xff1a;value指定数据库中的表名 如果我们不设置这个注解&#xff0c;我们操作的数据库的表就由BaseMapper 泛型决定&#xff08;SysLog&#xff09; TableName(value "sys_Log&qu…

学习动漫插画的网络班排行榜

很多小伙伴不知道动漫插画培训机构哪个好&#xff0c;找不到靠谱的插画班&#xff0c;今天给大家整理了国内动漫插画培训机构排名&#xff01; 一&#xff1a;动漫插画培训机构排名 1、轻微课&#xff08;五颗星&#xff09; 主打课程有日系插画、游戏原画、古风插画、动漫漫画…

python基于vue个人家庭理财记账管理系统

近年来在计算机的迅速发展的背景下&#xff0c;家庭理财领域与传统手工记账相比&#xff0c;使用计算机系统来管理不仅克服了地域上的局限性&#xff0c;而且增强了用户在时间和空间上的体验&#xff0c;以及能够让用户随时随地进行需要的操作&#xff0c;可以很好的规避传统的…

【建议收藏】Jenkins+postman+newman之API全自动化测试

1 背景 本文要介绍的环境在我司已经投入使用&#xff0c;举个简单的真实使用场景&#xff0c;开发提供了300多个API&#xff0c;每个API都有各种参数&#xff0c;所以我们会先在postman中为这300多个API编写300*n个testcase&#xff0c;然后在jenkins上跑&#xff1b;到此有人…

【Spark分布式内存计算框架——离线综合实战】2. 业务需求

1.3 业务需求 对广告数据进行初步ETL处理和业务报表统计分析&#xff0c;整体业务需求如下图所示&#xff1a; 两个主要方面的业务&#xff1a; 第一个、数据【ETL 处理】 依据IP地址&#xff0c;调用第三方库解析为省份province和城市city&#xff1b;将ETL后数据保存至PAR…

消费升级趋势下,平台如何在广告电商模式中攫取新流量

如今电商平台飞速发展&#xff0c;越来越多的人加入电商运营的行列&#xff0c;同行竞争逐渐变得激烈起来&#xff0c;为了能够让平台有更多的展现机会&#xff0c;提升平台的商品转化率&#xff0c;大家都很重视平台的优化&#xff0c;因为一个好的平台可以给自身带来更多的流…

比特数据结构与算法(第四章_上)树和二叉树和堆的概念及结构

1.树概念及结构1.1树的概念树是一种非线性的数据结构&#xff0c;它是由 n&#xff08;n > 0&#xff09;个有限节点组成的一个具有层次关系的集合。那么为什么叫 "树" 呢&#xff1f; &#xff08;节点也可以称结点&#xff0c;建议称结点&#xff0c;和结构体对…

REDIS中的缓存穿透,缓存击穿,缓存雪崩原因以及解决方案

需求引入一般在项目的开发中,都是使用关系型数据库来进行数据的存储&#xff0c;通常不会存在什么高并发的情况&#xff0c;可是一旦涉及大数据量的需求&#xff0c;比如商品抢购&#xff0c;网页活动导致的主页访问量瞬间增大&#xff0c;单一使用关系型数据库来保存数据的系统…

多孔弹性材料中传播的膨胀波方法(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密…

海量并发低延时 RTC-CDN 系统架构设计(下)

上半部分内容&#xff1a;海量并发低延时 RTC-CDN 系统架构设计&#xff08;上&#xff09;低延时 RTC-CDN 系统的架构传统 CDN 直播发展多年&#xff0c;为了优化延时&#xff0c;业界基本上朝两大优化方向&#xff1a;优化传输层协议和在传输层协议的基础上优化应用层协议。R…

Hadoop环境搭建(1)

一、在已安装的虚拟机上面进行修改&#xff08;以CentOS 7为例&#xff09;①修改主机名查看自己主机名&#xff0c;命令hostname第一种修改主机名方法&#xff0c;命令vi /etc/hostname第二种修改主机名方法&#xff0c;命令hostnamectl set -hostname 自定义主机名可以更改为…

简单介绍如何使用robotium进行自动化测试

创建一个简单的工程作为被测程序&#xff0c;运行后显示如下界面&#xff1a; 2.创建一个Test Project 1). 打开eclipse&#xff0c;选择File->New->Project…->Android Test Project&#xff0c;点击Next。 2). 在Test Project Name中输入测试工程的名称&#xff…

华为HCIP-Datacom认证题库(H12-821)

第一套&#xff08;100题&#xff09; 1. &#xff08;单选题&#xff09;下面关于0SPF的特殊区域&#xff0c;描述错误的是: A.Totally Stub Area允许ABR发布缺省的三类LSA,不接受五类LSA和细化三类LSA B.NSSA Area和Stub区域的不同在于该区域允许自治系统外部路由的引入&…

「实践总结」订单超时自动取消

在进行开发的过程中&#xff0c;在开发的时候&#xff0c;有遇到相关的延时支付相关的问题&#xff0c;在解决延时支付的相关的问题的时候&#xff0c;会有很多种的解决办法&#xff0c;现在就讲对应的解决办法先进行相关的总结操作&#xff1b;「引言」在开发中&#xff0c;往…

mysql索引失效的几种情况

失效的几种情况 1、select * from xxx 2、索引列上有计算 3、索引列上有函数 4、like左边包含‘%’ 5、使用or关键字 6、not in和not exists 7、order by 8、不满足最左匹配原则 给code、age和name这3个字段建好联合索引&#xff1a;idx_code_age_name。 该索引字段的顺…

ChatGPT告诉你:项目管理能干到60岁吗?

早上好&#xff0c;我是老原。这段时间最火的莫过于ChatGPT&#xff0c;从文章创作到论文写作&#xff0c;甚至编程序&#xff0c;简直厉害的不要不要的。本以为过几天热度就自然消退了&#xff0c;结果是愈演愈烈&#xff0c;热度未减……大家也从一开始得玩乐心态&#xff0c…

注意,这本2区SCI期刊最快18天录用,还差一步录用只因犯了这个错

发表案例分享&#xff1a; 2区医学综合类SCI&#xff0c;仅18天录用&#xff0c;录用后28天见刊 2023.02.10 | 见刊 2023.01.13 | Accepted 2023.01.11 | 提交返修稿 2022.12.26 | 提交论文至期刊部系统 录用截图来源&#xff1a;期刊部投稿系统 见刊截图来源&#xff1a…