数据结构(复杂度)

news2024/12/23 17:03:45

复杂度

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

时间复杂度主要衡量⼀个算法的运⾏快慢,⽽空间复杂度主要衡量⼀个算法运⾏所需要的额外空间。

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

时间复杂度

定义:在计算机科学中,算法的时间复杂度是⼀个函数式T(N),它定量描述了该算法的运⾏时间。时间复杂度是衡量程序的时间效率,那么为什么不去计算程序的运⾏时间呢?

1. 因为程序运⾏时间和编译环境和运⾏机器的配置都有关系,⽐如同⼀个算法程序,⽤⼀个⽼编译 器进⾏编译和新编译器编译,在同样机器下运⾏时间不同。

2. 同⼀个算法程序,⽤⼀个⽼低配置机器和新⾼配置机器,运⾏时间也不同。

3. 并且时间只能程序写好后测试,不能写程序前通过理论思想计算评估。

下面我们来看个案例:

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

Func1执⾏的基本操作次数:

T (N) = N^2+2∗N+10

• N=10   T(N)=130

• N=100  T(N)=10210 

• N=1000  T(N)=1002010 

通过对N取值分析,对结果影响最⼤的⼀项是N^2。

实际中我们计算时间复杂度时,计算的也不是程序的精确的执⾏次数,精确执⾏次数计算起来还是很⿇烦的(不同的⼀句程序代码,编译出的指令条数都是不⼀样的),计算出精确的执⾏次数意义也不⼤, 因为我么计算时间复杂度只是想⽐较算法程序的增⻓量级,也就是当N不断变⼤时T(N)的差别,上⾯我们已经看到了当N不断变⼤时常数和低阶项对结果的影响很⼩,所以我们只需要计算程序能代表增⻓量级的⼤概执⾏次数,复杂度的表⽰通常使⽤⼤O的渐进表⽰法

大O渐进表示法

⼤O符号(Big O notation):是⽤于描述函数渐进⾏为的数学符号。

推导大O阶的规则:

1. 时间复杂度函数式T(N)中,只保留最⾼阶项,去掉那些低阶项,因为当N不断变⼤时,低阶项对结果影响越来越⼩,当N⽆穷⼤时,就可以忽略不计了。

2. 如果最⾼阶项存在且不是1,则去除这个项⽬的常数系数,因为当N不断变⼤,这个系数对结果影响越来越⼩,当N⽆穷⼤时,就可以忽略不计了。

3. T(N)中如果没有N相关的项⽬,只有常数项,⽤常数1取代所有加法常数。

通过以上⽅法,可以得到 Func1 的时间复杂度为:O(N^2)

时间复杂度案例分析

案例一: 

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

 Func2执⾏的基本操作次数

F(N) = 2N + 10

根据推导规则第3条得出

Func2的时间复杂度为: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); 
}

Func3执⾏的基本操作次数

F (N) = M + N 

因此:Func3的时间复杂度为:O(M+N)

案例三:

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

Func4执⾏的基本操作次数

F (N) = 100

根据推导规则第1条得出

Func4的时间复杂度为O(1)

案例四:

// 计算strchr的时间复杂度? 
const char * strchr ( const char 
* str, int character)
{
 const char* p_begin = s;
 while (*p_begin != character)
 {
 if (*p_begin == '\0')
 return NULL;
 p_begin++;
}
 return p_begin;
}

strchr执⾏的基本操作次数

1)若要查找的字符在字符串第⼀个位置,则:F (N) = 1

2)若要查找的字符在字符串最后的⼀个位置, 则:F (N) = N 

3)若要查找的字符在字符串中间位置,则:F (N) = N/2 

因此:strchr的时间复杂度分为:

最好情况:O(1)

最坏情况:O(N)

平均情况:O(N)

小结:

通过上⾯我们会发现,有些算法的时间复杂度存在最好、平均和最坏情况。

最坏情况:任意输⼊规模的最⼤运⾏次数(上界)

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

最好情况:任意输⼊规模的最⼩运⾏次数(下界)

⼤O的渐进表⽰法在实际中⼀般情况关注的是算法的上界,也就是最坏运⾏情况。


案例五:

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

BubbleSort执⾏的基本操作次数

1)若数组有序,则:F (N) = N 

2)若数组有序且为降序,则:F (N) = (N∗(N + 1))/2

3)若要查找的字符在字符串中间位置,则为2)中情况的1/2.

因此:BubbleSort的时间复杂度取最差情况为:O(N^2).

案例六:

void func5(int n)
{
 int cnt = 1;
 while (cnt < n)
 {
 cnt *= 2;
 }
}

当n=2时,执⾏次数为1

当n=4时,执⾏次数为2

当n=16时,执⾏次数为4

假设执⾏次数为x ,则2^x = n

因此执⾏次数:x = log n

因此:func5的时间复杂度取最差情况为: O(log2 n)

*特别的,当n接近⽆穷⼤时,底数的⼤⼩对结果影响不⼤。因此,⼀般情况下不管底数是多少都可以省略不写,即可以表⽰为log n 。

案例七:

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

调⽤⼀次Fac函数的时间复杂度为O(1)

⽽在Fac函数中,存在n次递归调⽤Fac函数

因此:

阶乘递归的时间复杂度为:O(n)。


空间复杂度

空间复杂度也是⼀个数学表达式,是对⼀个算法在运⾏过程中因为算法的需要额外临时开辟的空间。空间复杂度不是程序占⽤了多少bytes的空间,因为常规情况每个对象⼤⼩差异不会很⼤,所以空间复杂度算的是变量的个数。

空间复杂度计算规则基本跟实践复杂度类似,也使⽤⼤O渐进表⽰法。

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

空间复杂度的计算示例

示例一:

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

函数栈帧在编译期间已经确定好了, 只需要关注函数在运⾏时额外申请的空间。

BubbleSort额外申请的空间有exchange等有限个局部变量,使⽤了常数个额外空间

因此空间复杂度为:O(1)

示例二:

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

Fac递归调⽤了N次,额外开辟了N个函数栈帧, 每个栈帧使⽤了常数个空间

因此空间复杂度为:O(N)


常见复杂度对比

小结

以上便是我对复杂度的分享,不是高手,但是有颗成为高手的心态,欢迎各位在评论区提出问题,纠正不足。感谢观看!

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

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

相关文章

1. 黑盒测试

黑盒测试 1. 黑盒测试定义 黑盒测试是一种软件测试技术&#xff0c;它可以检查软件的功能&#xff0c;而不会窥视其内部结构或编码。黑盒测试的主要来源是客户声明的要求规范。 黑盒测试的特点&#xff1a; 黑盒测试与软件的具体实现过程无关&#xff0c;如果实现过程发生了…

NetSuite RPA技术实践

近期有同学提出一个需求。 “需要存取的報表是存貨分類帳(stock ledger)&#xff0c;將查到的各個[Item|Location]作為一組key&#xff0c;分別將報表中的「期末庫存量」「期末平均成本」「期末庫存量價值」這三欄的值&#xff0c;在每個月月底的時候自動將這個報表的這三欄數…

毕设项目springboot+vue实现的在线求职平台

一、前言 随着信息技术的飞速发展和互联网的普及&#xff0c;线上求职已成为众多求职者和企业招聘的重要渠道。为满足市场需求&#xff0c;我们利用Spring Boot和Vue技术栈&#xff0c;开发了一款功能全面、用户友好的在线求职平台。本文将对该平台的设计、实现及关键技术进行详…

轻量级CRM系统精选:10款免费在线工具

本文将分享10款国内外免费轻量级在线CRM系统管理工具&#xff1a;八百客CRM、用友CRM、金蝶CRM、浪潮CRM、简信CRM、Agile CRM、Capsule CRM、EngageBay、SuiteCRM、Insightly。 在选择CRM系统时&#xff0c;中小企业常常面临预算有限、功能需求多样的困境。许多企业希望找到一…

Ubuntu新系统的使用

1.安装显卡驱动 直接到软件与更新里面&#xff0c;就是一个A字图标的那个软件打开&#xff0c;到附加驱动里选择。要选择“server driver”的&#xff0c;选择后确认即可。 然后输入&#xff1a;nvidia-sim查看 别的方法太复杂&#xff0c;这个方法我亲测了两台电脑&#xff…

《SpringCloud》系列文章目录

Spring Cloud为开发人员提供了工具&#xff0c;可以快速构建分布式系统中的一些常见模式&#xff08;例如配置管理、服务发现、断路器、智能路由、微代理、控制总线、短期微服务和合约测试&#xff09;。使用Spring Cloud开发人员可以快速建立实现这些模式的服务和应用程序。它…

昇思25天学习打卡营第10天|NLP-RNN实现情感分类

打卡 目录 打卡 任务说明 流程 数据准备与加载 加载预训练词向量&#xff08;分词&#xff09; 数据集预处理 模型构建 Embedding RNN(循环神经网络) LSTM 全连接层 损失函数与优化器 训练逻辑 评估指标和逻辑 模型训练与保存 模型加载与测试 自定义输入测试 …

leetcode算法题(反转链表)

思路1&#xff1a; 创建新的链表&#xff0c;遍历原链表&#xff0c;将原链表的节点进行头插到新链表中。 struct ListNode* reverseList(struct ListNode* head) {struct ListNode* next NULL;struct ListNode* new_head NULL;if (head NULL ||head->next NULL) // 空…

医院云HIS系统,以数字化形式提供医疗卫生行业的数据收集、存储、传递和处理服务

医院云HIS系统是一个运用云计算、大数据、物联网等新兴信息技术的业务和技术平台&#xff0c;旨在按照现代医疗卫生管理要求&#xff0c;以数字化形式提供医疗卫生行业的数据收集、存储、传递和处理服务。 具体来说&#xff0c;医院云HIS系统具有以下几个方面的特点和功能&…

MySQL事务隔离级别+共享锁,排他锁,乐观锁,悲观锁

在操作数据库的时候&#xff0c;可能会由于并发问题而引起的数据的不一致性&#xff08;数据冲突&#xff09;。 MySQL事务隔离级别 一个事务的执行&#xff0c;本质上就是一条工作线程在执行&#xff0c;当出现多个事务同时执行时&#xff0c;这种情况则被称之为并发事务&am…

node 如何运行typescript

文章目录 node 如何运行typescript手工编译 TypeScript 然后运行 JavaScript使用 ts-node创建一个typescript node项目tsconfig.json node 如何运行typescript 在 Node.js 中运行 TypeScript 代码有几种常见的方法,以下是其中几种。 手工编译 TypeScript 然后运行 JavaScript…

Docker---最详细的服务部署案例

提供python服务的docker一键部署&#xff0c;示例已配置负载均衡&#xff0c;不需要的在nginx.conf和docker-compose注释相关代码即可 文件结构 1、dockerfile # 服务的dockerfile# 服务依赖的镜像 FROM python:3.7# 设置容器内服务的工作目录 WORKDIR /app# 复制当前文件夹所…

数据库-三范式

第一范式 1 数据库所有字段都只有单一属性。 2 单一属性由基本数据类型构成。 3 数据库的表都是二维的行与列。 例如上面的例子就不满足第一范式&#xff0c;因为是可以继续拆分的&#xff0c;拆分为更多的属性。 第二范式 1 符合第一范式 2 表必须有个主建 3 其它字段可以…

企业网络运维-给华为交换机配置sftp,浏览交换机文件并下载上传

文章目录 需求实验开户stelnet权限已完成stelnet账号下的sftp配置使用xshell-sftp访问 需求 浏览交换机文件并下载上传 实验 开户stelnet权限 参考https://blog.csdn.net/xzzteach/article/details/140419150 已完成stelnet账号下的sftp配置 服务类型all包括stelnet和sf…

SadTalker数字人服务器部署

一、单独SadTalker部署 git clone https://github.com/OpenTalker/SadTalker.gitcd SadTalker conda create -n sadtalker python3.8conda activate sadtalkerpip install torch1.12.1cu113 torchvision0.13.1cu113 torchaudio0.12.1 --extra-index-url https://download.pyto…

NSSCTF中24网安培训day2中web题目

[SWPUCTF 2021 新生赛]ez_unserialize 这道题目考察php反序列化的知识点 打开题目&#xff0c;发现没有提示&#xff0c;我们试着用御剑扫描目录文件&#xff0c;发现存在robots.txt的文件 接着访问这个文件&#xff0c;发现是一段php反序列化代码&#xff0c;我们需要进行序…

[Windows] 油.管视频下载神器 Gihosoft TubeGet Pro v9.3.88

描述 对于经常在互联网上进行操作的学生&#xff0c;白领等&#xff01; 一款好用的软件总是能得心应手&#xff0c;事半功倍。 今天给大家带了一款高科技软件 管视频下载神器 无需额外付费&#xff0c;永久免费&#xff01; 亲测可运行&#xff01;&#xff01; 内容 目前主…

【B树、B-树、B+树】

目录 一、B-树&#xff08;即B树&#xff09;的定义及操作1.1、定义1.2、操作1.2.1、查找1.2.2、插入1.2.3、删除 二、B树的定义及操作2.1、定义2.2、操作2.2.1、查找2.2.2、插入2.2.3、删除 一、B-树&#xff08;即B树&#xff09;的定义及操作 1.1、定义 B-tree即B树&#…

jmeter-beanshell学习10-字符串补齐位数

每天都遇到新问题&#xff0c;今天又一个场景&#xff0c;一个字符串&#xff0c;如果不足11位&#xff0c;则左边补0&#xff0c;补够11位。 先要获取字符串长度&#xff0c;然后计算差多少位&#xff0c;补齐。今天又发现一个Object类型&#xff0c;这个类型有点厉害&#x…

uniapp启动图延时效果,启动图的配置

今天阐述uniapp开发中给启动图做延迟效果&#xff0c;不然启动图太快了&#xff0c;一闪就过去了&#xff1b; 一&#xff1a;修改配置文件&#xff1a;manifest.json "app-plus" : {"splashscreen" : {"alwaysShowBeforeRender" : false,"…