数据结构(三)复杂度的深层次剖析

news2024/11/28 6:27:15

之前发布了数据结构(一),很多同学反响不够清晰,那今天就发一篇对复杂度专题的博客,希望对大家理解复杂度提供一些帮助。

时间复杂度

我们先来一个理解一个复杂度,二分查找的复杂度(之前写过二分查找的专题博客,感兴趣的可以看一看)    CSDN

我们在数据结构(一)中讲解了,但是没有画图,现在为了方便大家的理解现在我重新讲解一下。

我们先把代码拿出来看看

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

这时候大家会好奇该如何计算其复杂度,其实搞清楚原理也比较容易理解。

二分查找的原理就不在过多的讲解了,不懂的小伙伴可以去看看上面的链接。

我们还是老样子画图来为大家演示:

当我们在不断地缩减,直到缩减到只剩下一个值的时候。

那么这就是最坏的一个情况,如果这个值是我们想要找的那个值,那么就找到了,如果不是那么我们输出找不到。

随之而来的疑问就是,我们一共找了多少次呢?

假设我们有N个值,我们每次都缩减一半,那么就是N/2,这是一次。那么我们一共找了多少次呢?

N/2/2/2/2/2/2.............=1 直到我们找到那个数为止。  这是最坏情况,那么我们除了多少个2呢?

不难看出,其实我们找了多少次就除了多少个2。

关键点拨:假设我找了X次,那么我们 就可以得到表达式。

第一步:N/2/2/2/2/2/2/2...............=1

第二步:N=1*2^x  (等式两边同时乘2)

第三步:2^x=N

第四步:化简

基本操作执行最好1次,最坏O(logN)次,时间复杂度为 O(logN) ps:logN在算法分析中表示是底
数为2,对数为N。有些地方会写成logN 。(由于对数在键盘中不好敲出来,所以我们通常省略2)。

补充时间复杂度例题:

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

大家看到这串代码时一定有想骂街的冲动,但是有我在大家不用担心,我来为大家搞定它。

那么开始进入正题:

上面的代码是 N 的阶乘的原码,之前我的博客也写过,感兴趣的小伙伴可以去看看地址就放在这里了-用C语言实现阶乘的相加-CSDN博客。

这里我们就直接开始,我们先思考一个问题,阶乘调用了多少次函数?

老样子画图解释:

我们不断调用FAC从N次到N-1次再到N-2次...........直到0次

我们把它们相加起来就可以得到。

计算分析发现基本操作递归了N次,时间复杂度为O(N)。

我们再来看难度比较大的一道题:

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

斐波那契我们用简单的图片来理解一下

理解起来有点像细胞分化的意思。

那么问题来了,一共有多少次调用呢?有个简易的方法来看一下

 我们观察最左边的数 2^0  2^1  2^2  2^3..........它们实际上是一个等比数列。

我们使用等比数列求和的方式求和.     这就用到了我们的高中知识。

通过计算分析发现基本操作递归了2^N次,时间复杂度为O(2^N)。

接下来为大家详解空间复杂度

空间复杂度

空间复杂度也是一个数学表达式,是对一个算法在运行过程中临时占用存储空间大小的量度 。
空间复杂度不是程序占用了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。空间复杂度计算规则基本跟实践复杂度类似,也使用大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;
}
}

结论:    实例1使用了常数个额外空间,所以空间复杂度为 O(1)

解释:空间复杂度是我们一个算法在运行时额外(由于逻辑的需要)开辟的空间。

上述代码算法(排序过程)额外开辟的有 size_t end     size_t i    exchange它们开辟的空间都是常数,所以使用大O渐进法不难算出空间复杂度。 O(1)

 如果大家对这道题有疑问的话我们再来看一道题,相信你的问题不在是问题了。

实例2:

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

我们观察在算法的运行中只动态开辟了(n+1)的空间。 ---------malloc((n+1)

那么我们使用大O渐进表示法:

动态开辟了N个空间,空间复杂度为 O(N)。

到这里我想大家对空间复杂度有了全新的理解了吧。

常见复杂度对比

一般算法常见的复杂度如下:

复杂度的oj练习 

消失的数字OJ链接:. - 力扣(LeetCode)

感谢你的观看

后续更新更多数据结构的相关知识

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

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

相关文章

JSONP 实现跨域请求案例

后端使用 express 搭建&#xff0c;案例代码如下&#xff1a; const express require(express)const app express() const PORT 3000app.get(/data, (req, res) > {const jsonData {name: Alan,age: 666,city: GD}const callback req.query.callback // 获取前端中的回…

野火ESP8266模块开发-基于Arduino IDE

一、野火ESP8266模块介绍 ESP8266 拥有高性能无线 SOC&#xff0c;给移动平台设计师带来福音&#xff0c;它以最低成本提供最大实用性&#xff0c;为 WiFi 功能嵌入其他系统提供无限可能。ESP8266 是一个完整且自成体系的 WiFi 网络解决方案&#xff0c;能够独立运行&#xff0…

网络工程师之路由交换技术篇

网络工程师之路由交换技术篇 路由交换之技术篇ARPICMPBPDUIPv6IP编址MAC其他技术点参考 以下均为个人笔记&#xff0c;摘录到csdn做备份 路由交换之技术篇 ARP Operation Code指定了ARP报文的类型&#xff0c; 包括ARP request 和ARP reply&#xff1b;取值为1或者2 &#x…

计算机毕业设计-基于深度学习的验证码识别方法设计与实现

概要 验证码是一个系统区分人类与非人类行为的有效方式。验证码识别技术能够使计算机程序输入正确的验证码&#xff0c;伪装成人类用户进入目标系统。另一方面&#xff0c;系统方面需要考虑破解验证码识别技术&#xff0c;修补验证方式的可能漏洞&#xff0c;使之能够更有效地区…

返回a除以b的余数 operator.mod(a, b) 返回a的b次幂 operator.pow(a, b)

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 返回a除以b的余数 operator.mod(a, b) 返回a的b次幂 operator.pow(a, b) [太阳]选择题 请问以下程序中operator.pow(2, 3)的执行结果是&#xff1a; import operator print("【执行】ope…

springboot284基于HTML5的问卷调查系统的设计与实现

问卷调查系统的设计与实现 摘 要 传统信息的管理大部分依赖于管理人员的手工登记与管理&#xff0c;然而&#xff0c;随着近些年信息技术的迅猛发展&#xff0c;让许多比较老套的信息管理模式进行了更新迭代&#xff0c;问卷信息因为其管理内容繁杂&#xff0c;管理数量繁多导…

【vue核心技术实战精讲】1.1 Vue开篇介绍 + 1.2 Vue的起步 和 插值表达式

文章目录 准备开始适应人群vue 框架学习路线一、vue 基础1、历史介绍2、前端框架与库的区别? 二、vue的起步 和 插值表达式Stage 1&#xff1a;下载包&#xff0c;并放入项目中Stage 2&#xff1a;编码 准备开始 适应人群 有一定的HTML/CSS/JavaScriptES6基础开发人员 vue …

深入解析MySQL数据库锁机制

✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心哦&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; ✨✨ 帅哥美女们&#xff0c;我们共同加油&#xff01;一起进步&am…

基于springboot+vue的光影视频网站

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

【机器学习智能硬件开发全解】(九)—— 政安晨:通过ARM-Linux掌握基本技能【C语言程序的预处理过程】

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 机器学习智能硬件开发全解 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; C语言程序的预处理过程是在编译阶段之前进行的&#x…

基础-笔试题6

1、tcp/udp是属于哪一层&#xff1f;tcp/udp有何优缺点&#xff1f; tcp /udp属于运输层 TCP 服务提供了数据流传输、可靠性、有效流控制、全双工操作和多路复用技术等。 与 TCP 不同&#xff0c; UDP 并不提供对 IP 协议的可靠机制、流控制以及错误恢复功能等。由于 UDP 比较…

[Qt学习笔记]Qt鼠标事件mouseMoveEvent实时获取图像的坐标和像素值

目录 1、介绍2、效果展示3、实现过程3.1 图像的加载和显示3.2 设置鼠标跟踪事件激活3.3 实现代码 4、源码展示 1、介绍 上一篇介绍了使用OpenCV的setMouseCallback回调函数实现获取鼠标点击点的图像坐标和像素值&#xff0c;本篇使用鼠标事件mouseMoveEvent函数来实现实时获取…

vue3+element Plus form 作为子组件,从父组件如何赋值?

刚开始接触vue3时&#xff0c;碰到一个很low的问题&#xff0c;将form作为子组件&#xff0c;在页面中给form表单项输入内容&#xff0c;输入框不显示值&#xff0c;知道问题出在哪&#xff0c;但因为vue3组合式api不熟悉&#xff0c;不知从哪下手... 效果图&#xff1a; 父组…

如何在iOS系统抓取log

前言&#xff1a;因为作者目前工作领域和苹果智能家居有关&#xff0c;然后发现一些bug其实是apple sdk原生code的问题&#xff0c;所以需要给apple提radar单&#xff0c;就需要抓ios端Log充当证据给apple看&#xff0c;其实ios抓log非常简单&#xff0c;大家感兴趣可以学习下哦…

Python条件语句深度解析:从基础到应用的全面指南

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! ​ 目录 &#x1f4d8; 一、引言 &#x1f4dd; 二、…

【Flutter】导航组件 NavigationRail 的用法简介

​​Material Design 3 定义了三种导航模式&#xff0c;其用法和对应的 Flutter 组件如下所示&#xff1a; MD3 导航Flutter 组件用途Navigation barBottomNavigationBar小型屏&#xff08;宽度小于640&#xff09;Navigation drawerDrawer大型屏&#xff08;宽度大于960&…

Java基础 学习笔记四

标识符 标识符是在源代码中程序员自己有权利命名的单词标识符可以标识 变量名&#xff0c;方法名&#xff0c;类名 标识符命名规则 标识符只能由数字&#xff0c;字符&#xff08;java支持所有国家语言&#xff09;&#xff0c;_&#xff0c; $ 组成&#xff0c;不能含有其他…

基于树莓派实现 --- 智能家居

最效果展示 演示视频链接&#xff1a;基于树莓派实现的智能家居_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Tr421n7BM/?spm_id_from333.999.0.0 &#xff08;PS&#xff1a;房屋模型的搭建是靠纸板箱和淘宝买的家居模型&#xff0c;户型参考了留学时短租的公寓~&a…

软考高级:软件测试阶段概念和例题

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

Linux课程____进程管理

记录工作日志 script 240319.log CTRLd 退出 cat 240319.log //查看 一、查看进程 1.静态 ps -aux ps -elf 2.动态 top 3.pgrep 查看特定条件的进程 pgrep -l “log” pgrep -l "ssh" pgrep -l -U redhat 4.pstree 查看进程树 pstree -aup 所有…