【马里奥数据结构吃“金币”】时间复杂度和空间复杂度

news2024/12/26 22:59:56

作者:一个喜欢猫咪的的程序员

专栏:《数据结构》

喜欢的话:世间因为少年的挺身而出,而更加瑰丽。                                  ——《人民日报》


 

目录

时间复杂度:

大O渐进表示法:

空间复杂度:

 常见复杂度对比:


 我们学数据结构之前我们已经写过了不少代码,我们在写代码的过程中,我们往往追求的是效率,那我们怎么来衡量一个代码的效率呢?

这就涉及到了本章的知识点:时间复杂度和空间复杂度!

因此衡量一个算法的好坏,一般是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度。

  • 时间复杂度主要衡量一个算法的运行快慢,
  • 空间复杂度主要衡量一个算法运行所需要的额外空间。

但我们一般比较在乎时间复杂度。


时间复杂度:

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

这里的函数指的是数学函数,而不是编程语言的函数。

执行的次数指的是循环的次数,以及递归时候函数调用的次数。

 我们先来看一个问题:下面这个代码执行了几次?

// 请计算一下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;
}
printf("%d\n", count);
}

我们结合下图来理解一下:圆圈一和圆圈二都循环了N次,而圆圈3 循环了2N次,圆圈4循环了M次。一和二是嵌套关系,圆圈一每循环一次圆圈二循环N次,所以N次圆圈一应该是执行了N^2。圆圈3和4都是普通的循环,所以三个加起来为:N^2+2N+M,这是一个具体的时间复杂度。

 而我们平常算的时间复杂度是一个大概值,我们运用了一种计算方法:大O渐进表示法!!!


大O渐进表示法:

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

推导大O阶方法:

1、用常数1取代运行时间中的所有加法常数。

2、在修改后的运行次数函数中,只保留最高阶项。

3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。

 我们观看这三个规则很抽象,我们下面通过一些例子来理解一下:

// 计算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);
}//O(2N+10)=O(N)

此代码我们容易算出它的具体的时间复杂度为2N+10。

我们这边利用了规则2和3,2N+10中2N为最高项,所以时间复杂度为2N,然后最高项2N存在,2这个常数去掉,所以最后是时间复杂度为O(N)。

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

本题跟前几题不太一样,因为本题的时间复杂度的具体值是一个参数(100)。

我们利用规则1,O(100)就变为了O(1)。

当我们以后面试或者考研面试的时候,我们经常是不看代码,以思想来算他的时间复杂度,我们来试一下不看代码算出冒泡排序(N个数)的时间复杂度:

void BubbleSort(int* a, int N)

我们假设它N个数进行冒泡排序,第一个数执行了N次,第二数N-1个数,第三个数N-2个数.......以此类推。第N个数就执行一次。那时间复杂度O(N+N-1+N-2+.....+1)。

这里就涉及到了等差数列,等差数列求和如下:

Sn=[n*(a1+an)]/2

那这里我们时间复杂度就变为O(0.5N^2+0.5N)=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;
}//O(logN)

 我们利用下图理解一下:

 我们在算数据结构的时间复杂度的时候。当遇到对数时,因为我们用键盘输入不了底数,所以我们经常把底数2省略,只写logN。但我们只省略2为底数的时候,当3(或者其他常数)为底数的时候,不省略。

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

当我们在算递归的时候,时间复杂度的具体值我们可以理解为:一次递归算一次,这里一共N次所以一共N次。

我们将这个题目改一下再来算一下:

// 计算阶乘递归Fac的时间复杂度?
long long Fac(size_t N)
{
if (1== N)
return 1;
for (int i = 0; i < N; i++)
{
;
}
return Fac(N - 1) * N;
}//O(N^2)

这里我们要算一下它具体的时间复杂度:

当为N时,循环N次;当为N-1时,循环N-1次;.......;当为1时,执行1次;

累加后为:N+N-1+N-2+....+1+N(递归的次数)=0.5N^2+1.5N;

 我们理解了这些例子再发过来理解一下规则:

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

推导大O阶方法:

1、用常数1取代运行时间中的所有加法常数。

2、在修改后的运行次数函数中,只保留最高阶项。

3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。


空间复杂度:

空间复杂度也是一个数学表达式,是对一个算法在运行过程中临时占用存储空间大小的量度空间复杂度不是程序占用了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数空间复杂度计算规则基本跟时间复杂度类似,也使用大O渐进表示法。

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

这里指的是是在函数内部临时开辟的空间的个数。

重复定义的话也算一个。

递归一次也算一个。

我们通过以下例子来看一下:(不再讲解已将答案写在每个代码最后)

// 计算Func4的空间复杂度?
void Func4(int N)
{
int count = 0;
for (int k = 0; k < 100; ++k)
{
++count;
}
printf("%d\n", count);
}//O(1)
// 计算Fibonacci的空间复杂度?
// 返回斐波那契数列的前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;
}//O(N)
// 计算阶乘递归Fac的空间复杂度?
long long Fac(size_t N)
{
if (N == 0)
return 1;
return Fac(N - 1) * N;
}//O(N)


 常见复杂度对比:

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

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

相关文章

文件操作学不会?快进来,带你深入理解->C语言文件操作

你将收获&#xff1a; 进一步理解缓冲区&#xff0c;以及引申出getchar(),scanf("%c",&c)接收数据时&#xff0c;易踩坑的地方&#xff0c;并对其解释。 w,r,a打开文件后如何正确使用读、写函数。 还有其它收获… 文件为什么存在什么是文件文件的唯一标识符缓冲文…

【FLASH存储器系列一】非易失性存储器基本原理之EPROM

1非易失性器件的存储原理 1.1最小存储单元-浮栅晶体管 我们当前使用的非易失性存储器的基本存储单元基本都是浮栅晶体管。技术在发展&#xff0c;浮栅晶体管的结构也在调整演进&#xff0c;接下来将用系列文章中的三篇分享EPROM、EEPROM、FLASH这三种非易失存储器件的基本存储…

麒麟系统开发笔记(九):在国产麒麟系统上搭建宇视摄像头SDK基础环境Demo

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/127532255 红胖子(红模仿)的博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软…

链路状态路由协议 OSPF (二)

作者简介&#xff1a;一名在校云计算网络运维学生、每天分享网络运维的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.Router ID 1.什么是Router ID 2.获得Router ID方法 二.DR和…

每日一题(day9)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录俩到经典题目一、走方格的方案数题目描述解题分析代码演示二.另类加法题目描述&#xff1a;解题分析常见的位运算代码演示总结俩到经典题目 一、走方格的方案数 题目…

【小嘟陪你刷题14】二叉树的最小深度、二叉树的所有路径、翻转二叉树

目录一、二叉树的最小深度思路一&#xff1a;深度优先搜索代码实现思路二&#xff1a;广度优先搜索代码实现二、二叉树的所有路径思路一&#xff1a;递归法代码实现思路二&#xff1a;迭代法三、翻转二叉树思路一&#xff1a;递归法代码实现思路二&#xff1a;迭代法代码实现一…

controller传输from-data数据格式的内容,取出传入数据为from-data格式的值

传输from-data数据格式的内容 postman里面的格式如下 接下来&#xff0c;便将上面的内容转换为代码 第一步&#xff1a;将File转为MultipartFile格式 首先&#xff0c;我们只能将File转为改格式才能进行网络传输&#xff0c;转换方式请看这篇博客&#xff1a;https://blog.…

推动行业数字化转型,亚马逊云科技自身就是“好把式”

&#xff08;亚马逊全球副总裁、亚马逊云科技大中华区执行董事张文翊&#xff09; 在2022年10月的亚马逊云科技中国峰会上&#xff0c;亚马逊云科技宣布了四大战略举措——“连中外、襄百业、携伙伴、促绿色“&#xff0c;进一步为中国本地客户赋能数字化探索与创新&#xff0…

顺序表实现—数据结构

文章目录一、顺序表概念及结构二、动态顺序表和静态顺序表的选择三、动态顺序表的实现逻辑&#xff08;1&#xff09;创建结构体&#xff08;2&#xff09;具体函数实现&#xff08;*&#xff09;顺序表初始化&#xff08;*&#xff09;释放顺序表&#xff08;*&#xff09;打印…

青少年python系列 21.turtle库绘制一个8

#绘制一个8import turtle#上方的小圆&#xff0c;圆心在左turtle.circle(80)#下方的大圆&#xff0c;圆心在右turtle.circle(-100)turtle.done() 青少年python教学视频ppt源码 青少年python系列目录_老程序员115的博客-CSDN博客 csdn文章推荐受影响解决办法10个字10行 csdn文…

梦开始的地方—— C语言指针入门

文章目录指针入门1.指针概念2. 指针和指针类型3. 野指针造成野指针的原因如何避免野指针4. 指针的运算指针加减整数指针的运算关系指针的关系运算5.指针和数组6. 二级指针7. 指针数组指针入门 1.指针概念 指针(Pointer) 是编程语言中的一个对象&#xff0c;利用地址&#xff…

31、Java——JDBC实现账号密码登录

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;乐趣国学的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&#xff1a;Java案例分…

Kong自动注册kong-spring-boot-stater

前言 kong-spring-boot-stater框架是为了解决SpringBoot项目和kong网关的自动注册&#xff0c;虽然Kong网关有提供可视化管理后台的操作界面&#xff0c;但是在多服务、多环境的时候在管理后台挨个配置每个服务节点是比较麻烦的&#xff0c;所以这也是kong-spring-boot-stater…

P3654 First Step (ファーストステップ)——暴力枚举

First Step (ファーストステップ) 题目背景 知らないことばかりなにもかもが&#xff08;どうしたらいいの&#xff1f;&#xff09; 一切的一切 尽是充满了未知数&#xff08;该如何是好&#xff09; それでも期待で足が軽いよ&#xff08;ジャンプだ&#xff01;&#xff09…

项目流程管理工具:OmniPlan Pro 4 中文

如何更好的管理项目流程&#xff1f;OmniPlan Pro 4中文是个很好的帮手&#xff0c;非常好用的项目流程管理工具&#xff0c; 强大的规划&#xff0c;管理复杂性&#xff1a; 引入三个新的内置模板&#xff1a;标准项目、标准项目&#xff08;样式&#xff09;和简单项目。 …

【TA】Unity角色二次元风格渲染

NRMToonLitSample Author : 文若 我的Demo地址 &#xff1a; NRMToonLitSample 学习视频地址 &#xff1a; Kerry大佬的 技术美术实战培训课程——卡通人物渲染方案 文章目录NRMToonLitSample1. 模型贴图基本信息2. 基础渲染效果2.1 基础shader Toon2.2 光照模型效果第一步&…

【从零到一的Raspberry】树莓派踩坑实录(一)系统安装与简单开发

写在前面 本系列作为树莓派上手记录&#xff0c;同时将本人的踩坑以及参考进行记录汇总&#xff0c;必要时罗列出小组分工&#xff0c;作为《嵌入式软开》小组参考文件。 0 硬件准备 名称描述树莓派3B支持wifi&#xff0c;包含了散热器、外壳、电源线等配件网线感谢王emo同学…

【小程序websocket前后端交互】uniapp写微信小程序聊天功能功能,websocket交互功能,心跳重连【详细注释,复制即用】

前言 这几天在做的一个需求&#xff0c;就是要写一个小程序端的页面&#xff0c;用于跟客服聊天。 然后就用到了websocket技术&#xff0c;以前我做过网页版的&#xff0c;但是做小程序后发现网页版的逻辑放过来没问题&#xff0c;但是很多的方法和api是不生效的&#xff0c;所…

立方体的表面积 长方体的表面积 公里转换为米 温度对照

立方体的表面积 难度&#xff1a;青铜 时间限制&#xff1a;1秒 占用内存&#xff1a;64 M 输入立方体边长&#xff0c;输出立方体的表面积。不考虑非法输入。格式 输入格式&#xff1a;输入实型 输出格式&#xff1a;输出实型 #include<bits/stdc.h> using namespace s…

万字长文的CSS与JavaScript简易学习

近期学习web笔记&#xff0c;可供参考 目录 css: css导入方式&#xff1a; css选择器&#xff1a; javascript: javascript介绍&#xff1a; js引入方式&#xff1a; js书写语法&#xff1a; js变量&#xff1a; 5种原始类型&#xff1a; 运算符&#xff1a; JavaScr…