数据结构1(初):时间复杂度和空间复杂度

目录

1、引言

1.1、什么是数据结构?

1.2、什么是算法?

1.3、如何学好数据结构和算法 ?

2、算法效率

2.1、如何衡量一个算法的好坏

2.2、算法的复杂度

3、时间复杂度

3.1、时间复杂度的概念

3.2、大O的渐进表示法

3.3、常见时间复杂度计算举例

4、空间复杂度

5、常见的复杂度对比

6、复杂度的oj练习


1、引言

1.1、什么是数据结构?

数据结构是计算机存储、组织数据的方式,指相互之间存在一种或多种特定关系的 数据元素的集合。(通俗的讲就是在内存中管理数据,增删查改)。

1.2、什么是算法?

算法就是定义良好的计算过程,他取一个或一组的值为输入,并产生出一个或一组值作为 输出。简单来说算法就是一系列的计算步骤,用来将输入数据转化成输出结果。(通俗的讲就是比如排序、二分查找等)

注:严格来讲就是算法和数据结构是不分家的,往往都是数据结构里面包含算法,算法里面包含数据结构。

1.3、如何学好数据结构和算法 ?

死磕代码,注意画图和思考(尤其是画图和思考)。

2、算法效率

2.1、如何衡量一个算法的好坏

比如对于以下斐波那契数列:

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

斐波那契数列的递归实现方式非常简洁,但简洁一定好吗?那该如何衡量其好与坏呢?

2.2、算法的复杂度

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

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

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

3、时间复杂度

3.1、时间复杂度的概念

时间复杂度的定义:在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。

一 个算法执行所耗费的时间,从理论上说,是不能算出来的,只有你把你的程序放在机器上跑起来,才能知 道。但是我们需要每个算法都上机测试吗?是可以都上机测试,但是这很麻烦。而且,比较两个程序的时间复杂度有一个前提条件就是在同一台机器上,因为不同的机器运算的速度也不一样。所以才有了时间复杂度这个分析方式。

一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法 的时间复杂度。

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

例如:

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

实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,确切来讲我们只关注时间复杂度的那个起决定性的部分,而忽略其他部分。

3.2、大O的渐进表示法

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

推导大O阶方法:

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

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

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

使用大O的渐进表示法以后,Func1的时间复杂度为:O(N^2)

通过上面我们会发现大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。

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

最坏情况:任意输入规模的最大运行次数(上界)

平均情况:任意输入规模的期望运行次数

最好情况:任意输入规模的最小运行次数(下界)

例如:

在一个长度为N数组中搜索一个数据x

最好情况:1次找到

最坏情况:N次找到

平均情况:N/2次找到

在实际中一般情况关注的是算法的最坏运行情况,所以数组中搜索数据时间复杂度为O(N)

3.3、常见时间复杂度计算举例

实例1:

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

实例1基本操作执行了2N+10次,通过推导大O阶方法知道,时间复杂度为 O(N)

实例2:

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

 实例2基本操作执行了M+N次,有两个未知数M和N,时间复杂度为 O(N+M)

实例3:

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

实例3基本操作执行了10次,通过推导大O阶方法,时间复杂度为 O(1)

注意:O(1)不是代表时间复杂度为1,而是代表常数次。

实例4:

// 计算strchr的时间复杂度?
const char* strchr(const char* str, int character)
{while (*str){if (*str == character){return str;}else{++str;}}
}

实例4基本操作执行最好1次,最坏N次,时间复杂度一般看最坏,时间复杂度为 O(N)

实例5:

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

实例5基本操作执行最好N次,最坏执行了N*(N+1)/2次(这个是通过等差数列的求和公式算出来的),通过推导大O阶方法+时间复杂度一般看最坏,时间复杂度为 O(N^2)

实例6:


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

实例6基本操作执行最好1次,最坏O(logN)次,时间复杂度为 O(logN)

假设有N个数据,设x为找了几次找到的,那么就有:N/(2^x)=1,化简可得:x=logN。

注意:logN在算法分析中表示是底数为2,对数为N。有些地方会写成lgN。

实例7:

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

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

实例8:

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

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

总结:我们关注的本质上是时间复杂度的量级,而不是精确值。

在上面时间复杂度的计算中我们并未用到很高级的数学知识,仅仅只是很简单的计算。

4、空间复杂度

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

空间复杂度不是程序占用了多少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)

实例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;
}

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

实例3:

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

实例3递归调用了N次,开辟了N个栈帧,每个栈帧使用了常数个空间。空间复杂度为O(N)

5、常见的复杂度对比

6、复杂度的oj练习

法一:(异或)时间复杂度为:O(N)

法二:(等差数列)时间复杂度为:O(N)

法一:(创建一个数组)时间复杂度为O(N),空间复杂度为O(N)

法二:(三段逆置)时间复杂度O(N)空间复杂度O(1)

欢迎读者到评论区交流或者私信。

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

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

相关文章

C语言自定义类型【联合体与枚举】

文章目录 1.联合体1.1联合体的声明1.2联合体的特点1.3联合体的大小计算联合体的使用案例 2.枚举2.1枚举类型的声明2.2枚举类型的优点(为什么使用枚举)2.3枚举类型的使用 结语 1.联合体 1.1联合体的声明 和结构体一样&#xff0c;联合体也是由一个或多个成员构成&#xff0c;同…

Atcoder Beginner Contest351 A-E Solution题解

文章目录 [A - The bottom of the ninth](https://atcoder.jp/contests/abc351/tasks/abc351_a)[B - Spot the Difference ](https://atcoder.jp/contests/abc351/tasks/abc351_b)[D - Grid and Magnet](https://atcoder.jp/contests/abc351/tasks/abc351_d)E Note&#xff1a;…

Rust 实战练习 - 12. Axum Web 简单demo

Rust Web 历程 Rust 的异步框架tokio非他莫属&#xff0c;而web框架一直是悬而未决&#xff0c;说到底还是因为没有官方成熟的方案指引&#xff0c;大家各玩各的&#xff0c;互不兼容&#xff0c;白白浪费精力。 这个事情一直等到半官方组织tokio推出axum有了改善。但是市场上…

如何将本地Android studio项目上传到GitHub

操作步骤&#xff1a; 1、在GitHub上创建账户 2、在androd studio中添加上述创建的GitHub账号 3、在android studio上找到"share project on GitHub"&#xff0c;点击此选项上传当前项目到GitHub 上传成功后&#xff0c;会在GitHub上创建默认仓库repository 注&a…

mysql-sql-练习题-2-窗口函数

窗口函数 访问量max sum建表窗口函数连接 直播间人数 第1、3名建表排名sum 访问量max sum 每个用户截止到每月为止&#xff0c;最大单月访问次数&#xff0c;累计到该月的总访问次数 建表 create table visit(uid1 varchar(5) comment 用户id,month1 varchar(10) comment 月…

阳光能源,创造永远:光模块的未来”:随着大数据、区块链、云计算和5G的发展,光模块成为满足不断增长的数据流量需求的关键技术

光模块的类型介绍&#xff1a; 为了适应不同的应用需求&#xff0c;不同参数和功能的光模块应运而生。光模块的分类方式及类型详见如下&#xff1a; &#x1f50e;封装形式&#x1f50d;&#xff1a; &#x1f4e3;&#x1f4e2;光模块按照封装形式来分有以下几种常见类型&a…

声光控路灯控制系统设计与仿真

目录 前言 一、设计任务 二、系统组成及工作原理 1、总体设计思路 2、电路各模块设计简介 &#xff08;1&#xff09;光控电路 &#xff08;2&#xff09;声控电路 (3) 逻辑控制电路 (4) 延时电路 三、系统中电源模块的设计 1、方案比较和确定 2、 设计思路 3、直流…

OpenHarmony实战开发-如何实现自定义绘制 (XComponent)

XComponent组件作为一种绘制组件&#xff0c;通常用于满足开发者较为复杂的自定义绘制需求&#xff0c;例如相机预览流的显示和游戏画面的绘制。 其可通过指定其type字段来实现不同的功能&#xff0c;主要有两个“surface”和“component”字段可供选择。 对于“surface”类型…

AcrelEMS-MH民航机场智慧能源管平台解决方案【可靠供电/降低能耗/高效运维】

民航机场行业背景 自2012年以来&#xff0c;我国民航运输规模出现了显著增长&#xff0c;旅客运输量&#xff1a;从2012年的3.19亿人次上升至2019年的6.6亿人次&#xff08;注&#xff1a;为剔除疫情影响&#xff0c;此处采取疫情前2019年的数据&#xff0c;下同&#xff09;&…

java:SpringBootWeb请求响应

Servlet 用java编写的服务器端程序 客户端发送请求至服务器 服务器启动并调用Servlet,Servlet根据客户端请求生成响应内容并将其传给服务器 服务器将响应返回给客户端 javaweb的工作原理 在SpringBoot进行web程序开发时,内置了一个核心的Servlet程序DispatcherServlet,称之…

【小迪安全2023】第59天:服务攻防-中间件安全CVE复现lSApacheTomcatNginx

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

SQL dialect is not configured. Apache Cassandra matches best.没有配置SQL方言 如何处理

我这里是MySQL语言,所以我设置MySQL dialect 写个记录,之后更换全局SQL语言再换 下图是设置

boot https ssl 使用http协议访问报错

在springboot中配置ssl以后&#xff0c; 再次使用http访问对应的接口就会报错 可以考虑如下设置&#xff0c;将http访问的端口重定向到https对应的端口 import org.apache.catalina.Context; import org.apache.catalina.connector.Connector; import org.apache.tomcat.util…

神经网络中多层卷积的作用

在神经网络中采用多层卷积的目的是为了逐步提取和组合图像的抽象特征&#xff0c;从而更有效地学习数据的表示并执行复杂的任务。不同层的卷积具有不同的作用&#xff0c;从较低层次的特征&#xff08;例如边缘、纹理&#xff09;到较高层次的抽象特征&#xff08;例如物体部件…

ZISUOJ 数据结构--串及其应用

说明&#xff1a; 都是字符串的基本操作没啥好说的&#xff0c;直接上题目和代码了。 题目列表&#xff1a; 问题 A: 字符串翻转 参考题解&#xff1a; #include <iostream> #include <string> #include <algorithm> using std::cin; using std::cout; usi…

OpenHarmony语言基础类库【@ohos.util.PlainArray (非线性容器PlainArray)】

PlainArray可用于存储具有关联关系的key-value键值对集合&#xff0c;存储元素中key值唯一&#xff0c;key值类型为number类型&#xff0c;每个key对应一个value。 PlainArray依据泛型定义&#xff0c;采用轻量级结构&#xff0c;集合中key值的查找依赖于二分查找算法&#xf…

数字电路-可预置倒计时器Multisim仿真

数字电路之于FPGA意义重大。本可预置倒计时器设计采用40106作为振荡电路&#xff0c;由74LSl92、74LS47D和七段共阴数码管构成计时电路&#xff0c;具有启动/预置、暂停/继续计时和报警功能。紫色文字是超链接&#xff0c;点击自动跳转至相关博文。持续更新&#xff0c;原创不易…

用C实现通讯录(详细讲解+源码)

前言 &#x1f4da;作者简介&#xff1a;爱编程的小马&#xff0c;正在学习C/C&#xff0c;Linux及MySQL.. &#x1f4da;以后会将数据结构收录为一个系列&#xff0c;敬请期待 ● 本期内容会给大家带来通讯录的讲解&#xff0c;主要是利用结构体来实现通讯录&#xff0c;该通讯…

[ESP32]:TFLite Micro推理CIFAR10模型

[ESP32]&#xff1a;TFLite Micro推理CIFAR10模型 模型训练 数据集处理 from keras.datasets import cifar10 from keras.preprocessing.image import ImageDataGenerator from keras.models import Sequential, load_model, Model from keras.layers import Input, Dense, …

xLua详解

目录 环境准备xLua导入 C#调用LuaLua解析器Lua文件加载重定向Lua解析管理器全局变量的获取全局函数的获取List和Dictionary映射table类映射table接口映射tableLuaTable映射table Lua调用C#准备工作Lua使用C#类Lua调用C#枚举Lua使用C# 数组 List 字典数组List字典 Lua使用C#扩展…