数据结构之算法复杂度

news2024/9/21 13:00:51

目录

前言

一、复杂度的概念

二、时间复杂度

三、大O的渐进表示法

四、空间复杂度

五、常见复杂度对比

总结



前言

        本文主要讲述数据结构中的算法复杂度


一、复杂度的概念

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

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

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


二、时间复杂度

在计算机科学中,算法的时间复杂度是一个函数式T(N),它定量描述了该算法的运行时间。时间复杂度是衡量程序的时间效率。

那么为什么不去计算程序的运行时间呢?

  1. 因为程序运行时间和编译环境和运行机器的配置都有关系,比如同一个算法程序,用⼀个老编译器进行编译和新编译器编译,在同样机器下运行时间不同。
  2. 同一个算法程序,用⼀个老低配置机器和新高配置机器,运行时间也不同。
  3. 并且时间只能程序写好后测试,不能写程序前通过理论思想计算评估。

那么算法的时间复杂度是一个函数式T(N),到底是什么呢?

答:这个T(N)函数式计算了程序的执行次数。

通过c语言编译链接章节学习,我们知道算法程序被编译后生成二进制指令,程序运行,就是cpu执行这些编译好的指令。那么我们通过程序代码或者理论思想计算出程序的执行次数的函数式T(N),假设每句指令执行时间基本一样(实际中有差别,但是微乎其微),那么执行次数和运行时间就是等比正相关, 这样也脱离了具体的编译运行环境。执行次数就可以代表程序时间效率的优劣。比如解决一个问题的算法a程序T(N)=N,算法b程序T(N)=N^2,那么算法a的效率⼀定优于算法b。

示例:

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

画图表示:

解析:实际中我们计算时间复杂度时,计算的也不是程序的精确的执行次数,精确执行次数计算起来还是很麻烦的(不同的⼀句程序代码,编译出的指令条数都是不⼀样的),计算出精确的执行次数意义也不大, 因为我们计算时间复杂度只是想比较算法程序的增长量级,也就是当N不断变大时T(N)的差别,上面我们已经看到了当N不断变大时常数和低阶项对结果的影响很小,所以我们只需要计算程序能代表增长量级的大概执行次数,复杂度的表示通常使用大O的渐进表示法。


三、大O的渐进表示法

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

推导大O阶规则:

  1. 时间复杂度函数式 T(N) 中,只保留最高阶项,去掉那些低阶项,因为当 N 不断变大时, 低阶项对结果影响越来越小,当 N 无穷大时,就可以忽略不计了。
  2. 如果最高阶项存在且不是 1 ,则去除这个项目的常数系数,因为当 N 不断变大,这个系数对结果影响越来越小,当 N 无穷大时,就可以忽略不计了。
  3. T(N) 中如果没有 N 相关的项目,只有常数项,用常数 1 取代所有加法常数

通过大O渐进表示法,我们可以推出上述 Func1 的时间复杂度了:(因为主要是++count的运行次数,所以时间复杂度也是主要计算它的运行次数)

 

示例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);
}

画图表示:


示例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);
}

画面表示:

解释:如果M>>N,则时间复杂度可以为O(M),反之N>>M,则时间复杂度可以写成O(N),如果M==N,则时间复杂度为O(M+N)


示例3:

//计算Func4的时间复杂度?

void Func4(int N)
{
	int count = 0;
	for (int k = 0; k < 100; ++k)
	{
		++count;
	}
	printf("%d\n", count);
}

画图表示:


示例4:

//计算strchr的时间复杂度?

const char* strchr(const char
	* str, int character)
{
	const char* p_begin = str;
	while (*p_begin != character)
	{
		if (*p_begin == '\0')
			return NULL;
		p_begin++;
	}
	return p_begin;
}

画图表示:

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

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

大O的渐进表示法在实际中一般情况关注的是算法的上界,也就是最坏运行情况。

因此示例4的时间复杂度应该为: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;
	}
}

画图表示:


示例6:对数的计算

//求时间复杂度

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

画图表示:

注:log 的底数可写可不写,如果底数为10可写成 lg


示例7:递归的计算

//计算阶乘递归Fac的时间复杂度?

long long Fac(size_t N)
{
	if (0 == N)
		return 1;
	return Fac(N - 1) * N;
}

画图表示:


四、空间复杂度

空间复杂度也是一个数学表达式,是对一个算法在运行过程中因为算法的需要额外临时开辟的空间。

空间复杂度计算规则基本跟时间复杂度类似,也使用大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;
	}
}

画图表示:

示例2:递归函数

//计算阶乘递归Fac的空间复杂度?

long long Fac(size_t N)
{
	if (N == 0)
		return 1;
	return Fac(N - 1) * N;
}

画图表示:


五、常见复杂度对比

常见的复杂度有:n、logn、n*logn、n的平方、n的三次方、2的n次方、n的阶乘

解析:很明显,n的平方、n的三次方、2的n次方、n的阶乘这些复杂度都比较高。而n、logn、n*logn这些复杂度就比较低,算法的效率比较高。


总结

        以上就是本文的全部内容,感谢支持

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

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

相关文章

【Node】如何关闭node被占用的端口

现象&#xff1a; 服务端口被占用Error: listen EADDRINUSE: address already in use :::10088 解决办法&#xff1a; 解决的思路就是把对应10088端口运行的程序给杀死。 1.去cmd输入 cd c:\Windows\System322.可以查看所有端口获取PID netstat -ano3.也可以用端口准确定位…

linux如何对c++进行内存分析

linux如何对c进行内存分析 背景分析方法以及原理原理分析结果以及重点关注 背景 在工作中&#xff0c;我遇到一个问题&#xff0c;需要将c写的进程部署到MCU上。由于MCU上可用的RAM 非常有限&#xff0c;所以在部署时就需要考虑到使用内存大小。所以为了搞清楚&#xff0c;内存…

大模型Qwen2.5 家族的最新成员

阿里今天发布了 Qwen 家族的最新成员&#xff1a;Qwen2.5&#xff0c;包括语言模型 Qwen2.5&#xff0c;以及专门针对编程的 Qwen2.5-Coder 和数学的 Qwen2.5-Math 模型。 所有开放权重的模型都是稠密的、decoder-only 的语言模型&#xff0c;提供多种不同规模的版本&#xff…

vue3+Element-plus el-input 输入框组件二次封装(支持金额、整数、电话、小数、身份证、小数点位数控制,金额显示中文提示等功能)

一、效果图 二、组件集成了以下功能 1、输入金额--支持千分号显示、可设置decimalLimit来调整小数点位数 2、金额鼠标移入提示中文--标签添加isTip开启中文提示则不允许开启千分号显示showThousands 3、输入手机号--设置inputTypephone 4、输入整数---设置inputTypeinteger 5、…

14.1.2-float浮动练习

文章目录 1. 目标2. 实现 1. 目标 只通过float来做下面的布局&#xff08;不使用flex&#xff09;。 2. 实现 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widt…

Autosar Dcm开发-诊断2E或31服务实现pending功能

文章目录 前言Dcm规范功能实现总结前言 项目开发过程中,有需求在31服务(Routine)收到请求时,等待应用层反馈执行完后再进行响应。所以pending一段时间,本文介绍该功能的实现。 Dcm规范 以Routine为例,其服务包含以下返回状态 0:E_OK,服务成功执行 1:E_NOT_OK,服务…

【大屏方案】可视化综合展示系统解决方案(Word原件2024)

2.系统架构设计 2.1.系统架构图 2.2.关键技术 2.3.接口及要求 3.系统功能设计 3.1.功能清单列表 3.2.数据源管理 3.3.数据集管理 3.4.视图管理 3.5.仪表盘管理 3.6.移动端设计 3.1.系统权限设计 3.2.数据查询过程设计 软件资料清单列表部分文档清单&#xff1a;工作安排任务书&…

滑动条QSlider

可以在一个范围内拖动。 常用属性和方法 值 包括当前值、最大值、最小值 // 获取和设置当前值 int value() const; void setValue(int);// 获取和设置最大值 int maximum() const; void setMaximum(int);// 获取和设置最小值 int minimum() const; void setMinimum(int);//…

关于 NLP 深度学习的核心流程

基本流程实现的先后顺序&#xff08;每一步都包含很多技术点&#xff09;&#xff1a; 选定语言模型结构 关于语言模型&#xff1a; 作用 判断那一句话相对更合理&#xff0c;相对不合理的会得到较底的分值&#xff1a; 挑选成句概率分值最高的评价指标&#xff1a;PPL&…

一个能同时to B和to C、批发零售一体化的需求分析和系统设计

一些企业纠结自己的模式是to B还是to C&#xff0c;一些企业在to B和to C中转型&#xff0c;还有一些企业在做着to B的业务&#xff0c;也在做to C的代发&#xff0c;这些企业在不停地变更着业务&#xff0c;更换着系统&#xff0c;给企业带来巨大的资金和时间成本&#xff0c;…

ssrf攻击fastcgi复现及环境搭建

目录 一、环境 二、开始操作 一、环境 网上自己找vulhub-master.zip&#xff0c;我这里没用docker&#xff0c;本地自己搭建的 二、开始操作 很明显的ssrf漏洞 很明显我们之前的协议file dict 很明显9000端口是开放的 我们还是用gopherus生成一下 我们环境机上很明显有PEAR…

ESP8266+DHT11+Python制作一个物联网温湿度传感器

ESP8266是一款低功耗、高集成度的Wi-Fi SOC&#xff08;System on Chip&#xff0c;系统级芯片&#xff09;&#xff0c;这款芯片专为物联网&#xff08;IoT&#xff09;应用而设计&#xff0c;常见开发ESP8266的环境可以使用Arduino或者ESP8266 RTOS SDK、NodeMCU&#xff0c;…

乐观锁、悲观锁及死锁

乐观锁、悲观锁 1.概念 悲观锁(悲观锁定)&#xff1a;具有强烈的独占和排他特性。在整个执行过程中&#xff0c;将处于锁定状态。悲观锁在持有数据的时候总会把资源或者数据锁住&#xff0c;这样其他线程想要请求这个资源的时候就会阻塞&#xff0c;直到等到悲观锁把资源释放为…

QFramework v1.0 使用指南 更新篇:20240919. 新增 BindableDictionary

虽然笔者目前还不知道 BindableDictionary 能用在什么使用场景下&#xff0c;但是还是应童鞋的要求实现了 BindableDictionary。 基本使用如下: using System.Linq; using UnityEngine;namespace QFramework.Example {public class BindableDictionaryExample : MonoBehaviou…

《让手机秒变超级电脑!ToDesk云电脑、易腾云、青椒云移动端评测》

前言 科技发展到如今2024年&#xff0c;可以说每一年都在发生翻天覆地的变化。而云上这个词时常都被大家提起&#xff0c;从个人设备连接到云端在如今在也不是梦了。而云电脑这个市场近年来迅速发展&#xff0c;无需购买和维护额外的硬件就可以体验到电脑端顶配的性能和体验&am…

Adams与Matlab通过FMI联合仿真

Adams与Matlab的联合仿真通过Adams/Controls中的接口功能已经很早就实现&#xff0c;具体是通过Adams安装路径下的支持文件&#xff0c;利用Adams/Controls中的导出功能&#xff0c;将Adams模型生成模型文件以及同Matlab的接口文件*.m&#xff0c;然后在Matlab中执行该*.m文件后…

使用SoapUI、Postman工具调用Webservice方法

SoapUI工具更适合调用Webservice使用。 1.使用SoapUI工具调用Webservice 创建“New SOAP Project” 自行定义一个项目名称&#xff0c;输入wsdl地址&#xff1a; 在左侧列表找到方法名&#xff0c;双击“Request 1”, 在请求数据中&#xff0c;添加对应的参数&#xff0c;然…

Linux文件IO(五)-三种进程退出方法及空洞文件

1.三种进程退出方法 return 当程序在执行某个函数出错的时候&#xff0c;如果此函数执行失败会导致后面的步骤不能在进行下去时&#xff0c;应该在出错时终止程序运行&#xff0c;不应该让程序继续运行下去&#xff0c;那么如何退出程序、终止程序运行呢&#xff1f;有过编程…

面试面经|大模型算法岗常见面试题100道

本文提供了一份全面的大模型算法岗位面试题清单&#xff0c;包括基础理论、模型结构、训练微调策略、应用框架、分布式训练和模型推理等方面的知识点&#xff0c;旨在帮助求职者准备相关技术面试。 一、基础篇 1、目前主流的开源模型体系有哪些&#xff1f; Transformer体系&a…

RTX NVIDIA 3090卡配置对应pytorch,CUDA版本,NVIDIA驱动过程及问题整理

买了两块3090卡闲置很长时间了&#xff0c;之前tf 1.12.0版本用习惯了不想转工具。这段时间闲下来转了之后有些环境不适配&#xff0c;在雷神帮助下安装完毕&#xff0c;虽然出了点怪东西&#xff0c;整体还好。 原环境CUDA为11.4 其他配置如下 之前conda install的pytorch实为…