【数据结构】复杂度

🔥博客主页:小王又困了

📚系列专栏:数据结构

🌟人之为学,不日近则日退 

❤️感谢大家点赞👍收藏⭐评论✍️


目录

一、什么是数据结构

二、什么是算法

三、算法的效率

四、时间复杂度

4.1大O渐进表示法

4.2常见时间复杂度计算举例

4.3例题:消失的数字

五、空间复杂度 

5.1空间复杂度计算 

5.2例题:轮转数组


🗒️前言

在前面我们讲完了C语言的内容,从本期开始我们将进入数据结构的学习,本期介绍了数据结构的概念和算法分析的初步知识。

一、什么是数据结构

数据结构(Data Structure)是计算机存储、组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合。

二、什么是算法

算法(Algorithm)是定义良好的计算过程,它取一个或一组的值为输入,并产生出一个或一组值作为输出。简单来说算法就是一系列的计算步骤,用来将输入数据转化成输出结果

三、算法的效率

我们会通过复杂度去衡量一个算法的好坏。算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源 。因此衡量一个算法的好坏,一般是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度。

时间复杂度主要衡量一个算法的运行快慢,而空间复杂度主要衡量一个算法运行所需要的额外空间。在计算机发展的早期,计算机的存储容量很小。所以对空间复杂度很是在乎。但是经过计算机行业的迅速发展,计 算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注一个算法的空间复杂度。

四、时间复杂度

时间复杂度的概念

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

即:找到某条基本语句与问题规模N之间的数学表达式,就是算出了该算法的时间复杂度。

4.1大O渐进表示法

实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,所以这里我们使用大O的渐进表示法。 

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

推导大O阶方法:

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

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

  3.如果最高阶项存的系数不为1,则去除这个项的系数。

另外有些算法的时间复杂度存在最好、平均和最坏情况:

  • 最坏情况:                                                                                                                                   任意输入规模的最大运行次数(上界)
  • 平均情况:                                                                                                                                 任意输入规模的期望运行次数
  • 最好情况:                                                                                                                               任意输入规模的最小运行次数(下界)

说明:在实际中一般情况关注的是算法的最坏运行情况。

4.2常见时间复杂度计算举例

🚩冒泡排序:

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

📒最好情况:O(N)

        最好情况就是数组本身有序,虽然它有序,但是计算机最初并不知道它是有序的,仍需要遍历一遍数组才能知道它是有序的,所以就好情况就是O(N)。

📒最坏情况:O(N^2)

        最坏情况是数组完全逆序,则第一趟需要交换N − 1 次,第二趟需要交换N − 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;elsereturn mid;}return -1;
}

📒最好形况:O(1)

        最好情况是第一次查找就找到目标值,此时时间复杂度就是O(1)。

📒最坏情况:O(log2N)
        二分查找每次可以排出一半的数据,就坏的情况就是排出到只剩下一个数据。当N/2/2/2/2……/2=1时,就找到了目标值。除去了几个2就是执行的次数,所以时间复杂度为O(log2N)。

O(N)和O(log2N)的对比:

N1000100W10亿
O(N)1000100W10亿
O(log2N)102030

由此我们看到O(log2N)相对O(N)在效率上有很大的提升,但二分查找有一个限制条件就是数组必须有序,所以在实际中二分查找应用并不多。

🚩递归阶乘

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

📒时间复杂度:O(N)

        Fac一共被递归调用了N+1次,且每次Fac中执行1次,总共执行N+1次,所以时间复杂度是O(N)。

🚩斐波那契数

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

 📒时间复杂度:O(2^N)

        斐波那契额数列,它的时间复杂度是等比数列求和,所以时间复杂度为O(2^N)。

4.3例题:消失的数字

💡思路一: 

        我们可以把0~N个数字全部加起来,减去数组中的元素,结果就是消失的数字。

时间复杂度为O(N)

int missingNumber(int* nums, int numsSize)
{int i=0;int ret=N*N/2;for(i=0;i<numsSize;i++){ret-=nums[i];}return ret;
}

💡思路二:

        我们可以使用异或,异或的条件是相同为0,相异为1。两个相同的数异或为0,0和任何数异或都为原数,所以我们将0~N与数组中的所有异或,得到的结果就是消失的数。

int missingNumber(int* nums, int numsSize)
{int m=0;int i=0;for(i=0;i<=numsSize;i++){m^=i;}for(i=0;i<numsSize;i++){m^=nums[i];}return m;
}

五、空间复杂度 

空间复杂度的概念:

空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度 。 空间复杂度不是程序占用了多少bytes的空间,而算的是变量的个数。 空间复杂度计算规则也使用大O渐进表示法。

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

一般常见的空间复杂度都是O(1)或者O(N)(额外开辟数组)。

5.1空间复杂度计算 

🚩递归阶乘:

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

📒空间复杂度:O(N)

        函数的每一次调用都会开辟一个栈帧,每个栈帧开常数个空间,开辟N+1个栈帧,空间复杂度就为O(N)。

 递归程序最大的问题就是深度太深,会有栈溢出的风险。

🚩 斐波那契数

long long Fib(size_t N)
{if(N < 3)return 1;return Fib(N-1) + Fib(N-2);
}

📒空间复杂度:O(N)

        空间是可以重复利用的,递归的调用是按一条线递归下去的,不会同时递归,当递归到最后一层返回时,创建的函数栈帧销毁,调用另一条仍可以使用这块空间,所以空间复杂度是O(N)。

5.2例题:轮转数组

 💡思路

  1. 逆置前n-k个
  2. 逆置后k个
  3. 整体逆置
void reverse(int* nums,int left,int right)
{int tmp=0;while(left<=j){tmp=nums[left];nums[left]=nums[right];nums[right]=tmp;left++;right--;         }
}void rotate(int* nums, int numsSize, int k)
{if(k==0){return nums;}reverse(nums,0,numsSize-1);reverse(nums,0,k%numsSize-1);reverse(nums,k%numsSize,numsSize-1);
}

本次的内容到这里就结束啦。希望大家阅读完可以有所收获,同时也感谢各位读者三连支持。文章有问题可以在评论区留言,博主一定认真认真修改,以后写出更好的文章。你们的支持就是博主最大的动力。

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

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

相关文章

k8s基础

k8s基础 文章目录 k8s基础一、k8s组件二、k8s组件作用1.master节点2.worker node节点 三、K8S创建Pod的工作流程&#xff1f;四、K8S资源对象1.Pod2.Pod控制器3.service && ingress 五、K8S资源配置信息六、K8s部署1.K8S二进制部署2.K8S kubeadm搭建 七、K8s网络八、K8…

人大金仓三大兼容:Oracle迁移无忧

企业级应用早期的架构模式是C/S&#xff08;Client/Server&#xff09;模式&#xff0c;Client做人机交互逻辑的呈现&#xff0c;Sever做业务计算逻辑的实现。这就类似餐馆的运作模式&#xff0c;Client是前台的服务员提供点菜和上菜服务&#xff0c;而Server则是后厨完成菜品的…

设计模式之工厂方法模式(FactoryMethod)

一、概述 定义一个用于创建对象的接口&#xff0c;让子类决定实例化哪一个类。FactoryMethod使一个类的实例化延迟到其子类。 二、适用性 1.当一个类不知道它所必须创建的对象的类的时候。 2.当一个类希望由它的子类来指定它所创建的对象的时候。 3.当类将创建对象的职责委…

vue生命周期解析

Vue.js 是一个流行的前端 JavaScript 框架&#xff0c;它提供了一种用于构建用户界面的渐进式方法。Vue 组件的生命周期钩子函数是一些特定的函数&#xff0c;它们在组件不同阶段被自动调用&#xff0c;可以让你在这些阶段执行特定的逻辑。下面是 Vue 组件的生命周期钩子函数以…

【Spring】核心容器——Setter注入

1、引入 首先引入Spring框架依赖 <dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.6.RELEASE</version> </dependency> 在dao层和service层分别准备两个接口以及他…

Stable Diffuion webui Mac版本安装过程

系统环境 操作系统&#xff1a;MacOS Ventura13.5 芯片&#xff1a;Apple M2 Max Python: 3.10 安装前置准备 git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git注意事项&#xff1a;修改源码内全部 git clone 链接&#xff0c;设置代理 https://ghpr…

26 | 谷歌应用APP数据分析

基于kaggle公开数据集,对谷歌应用市场的APP情况进行数据探索和分析。 from kaggle: https://www.kaggle.com/lava18/google-play-store-apps 分析思路: 0、数据准备 1、数据概览 2、种类对Rating的影响 3、定价策略 4、因素相关性分析 5、用户评价 6、总结 0、数据准备 (…

Fast SAM与YOLOV8检测模型一起使用实现实例分割以及指定物体分割

Fast SAM与YOLOV8检测模型一起使用 部分源代码在结尾处可获取 晓理紫 1 使用场景 实例分割数据集的获取要比检测数据的获取更加困难&#xff0c;在已有检测模型不想从新标注分割数据进行训练但是又想获取相关物体的mask信息以便从像素级别对物体进行操作&#xff0c;这时就可以…

学习内容散记

git下载网址 &#xff1a;https://registry.npmmirror.com/binary.html?pathgit-for-windows/ error: remote origin already exists 如果你clone下来一个别人的仓库&#xff0c;在此基础上完成你的代码&#xff0c;推送到自己的仓库可能遇到如下问题&#xff1a; error: r…

uniapp开发(由浅到深)

文章目录 1. 项目构建1.1 脚手架构建1.2 HBuilderX创建 uni-app项目步骤&#xff1a; 2 . 包依赖2.1 uView2.2 使用uni原生ui插件2.3 uni-modules2.4 vuex使用 3.跨平台兼容3.1 条件编译 4.API 使用4.1 正逆参数传递 5. 接口封装6. 多端打包3.1 微信小程序3.2 打包App3.2.1 自有…

PHP“牵手”京东商品详情数据获取方法,京东商品详情API接口申请指南

京东详情接口 API 是淘宝开放平台提供的一种 API 接口&#xff0c;它可以帮助开发者获取淘宝商品的详细信息&#xff0c;包括商品的标题、描述、图片等信息。在淘宝电商平台的开发中&#xff0c;京东详情接口 API 是非常常用的 API&#xff0c;因此本文将详细介绍京东详情接口 …

VS+QT+Opencv使用YOLOv4对视频流进行目标检测

对单张图像的检测&#xff0c;请参考&#xff1a;https://blog.csdn.net/qq_45445740/article/details/109659938 #include <fstream> #include <sstream> #include <iostream> #include <opencv2/dnn.hpp> #include <opencv2/imgproc.hpp> #inc…

支付整体架构

5.4 支付的技术架构 架构即未来&#xff0c;只有建立在技术架构设计良好的体系上&#xff0c;支付机构才能有美好的未来。如果支付的技术体系在架构上存在问题&#xff0c;那么就没有办法实现高可用性、高安全性、高效率和水平可扩展性。 总结多年来在海内外支付机构主持和参与…

C语言之位运算

一、什么是位运算 所谓位运算是指进行二进制位的运算 在系统软件中&#xff0c;常要处理二进位的问题 例如&#xff0c;将一个存储单元中的各二进位左移或右移一位&#xff0c;两个数按位相加等 二、位运算符和位运算 1、按位与 运算符(&) 参加运算的两个数据&#xff…

php 常用调试方式

要在PHP命令行中配置Xdebug&#xff0c;您需要完成以下步骤&#xff1a; 安装Xdebug扩展&#xff1a;首先&#xff0c;确保已经安装了Xdebug扩展。您可以通过在终端中运行php -m来检查是否安装了Xdebug扩展。如果没有安装&#xff0c;您可以按照官方文档或适用于您所使用的操作…

python正则表达式详解笔记,python正则表达式教学

正则表达式 正则表达式是一个特殊的字符序列&#xff0c;计算机科学的一个概念。通常被用来检索、替换那些符合某个模式(规则)的文本。 许多程序设计语言都支持利用正则表达式进行字符串操作。在Python中需要通过正则表达式对字符串进行匹配的时候&#xff0c;可以使用re模块…

Exploiting Proximity-Aware Tasks for Embodied Social Navigation 论文阅读

论文信息 题目&#xff1a;Exploiting Proximity-Aware Tasks for Embodied Social Navigation 作者&#xff1a;Enrico Cancelli&#xff0c; Tommaso Campari 来源&#xff1a;arXiv 时间&#xff1a;2023 Abstract 学习如何在封闭且空间受限的室内环境中在人类之间导航&a…

uniapp 获取 view 的宽度、高度以及上下左右左边界位置

<view class"cont-box"></view> /* 获取节点信息的对象 */ getElementRect() {const query uni.createSelectorQuery().in(this);query.select(".cont-box").boundingClientRect(res > {console.log(res);console.log(res.height); // 10…

Taro UI中的AtTabs

TaroUI 中的 AtTabs 是一个用于创建标签页(tab)组件的组件。它提供了一种简单的方式来切换显示不同的内容。 AtTabs 的使用方式如下&#xff1a; 首先&#xff0c;引入 AtTabs 组件和必要的样式&#xff1a; import { AtTabs, AtTabsPane } from taro-ui import taro-ui/dis…

Kubernetes系列-删除deployment和pod

通过deployment创建的pod直接执行delete是不会正常被删除的&#xff0c;因为deployment中设置了pod的数量&#xff0c;deployment会动态维护pod的数量&#xff0c;倘若pod数量少于约定数量&#xff0c;deployment会创建pod&#xff0c;直到pod数量达到约定数量才会停止。 如若…