数据结构初阶(C语言)-复杂度的介绍

news2024/11/13 14:35:16

       在学习顺序表之前,我们需要先了解下什么是复杂度:

一,复杂度的概念

       我们在进行代码的写作时,通常需要用到许多算法,而这些算法又有优劣之分,区分算法的优劣则是通过算法的时间复杂度和空间复杂度来决定。

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

二,时间复杂度

2.1定义

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

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

2. 同⼀个算法程序,用⼀个老低配置机器和新高配置机器,运行时间也不同。

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

而这里我们所说的T(N)即为程序所执行的次数,下面我们来看一个例子:
 

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

       可以看到,这条语句中,++count这条语句被执行的次数为N*N+2*N+10,即T(N)= N*N+2*N+10。

       但在实际情况中,对于程序的执行次数的计算非常的麻烦,我们通常不使用以上的方式来计算时间复杂度,而是用粗略值O(N)来估算,使用的是大O的渐进表示法。

2.2大O的渐进表示法

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

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

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

所以我们可以计算出上面的例子的时间复杂度为O(N*N)。(平方打不出来求放过)

2.3大O的渐进法表示时间复杂度的几道例题

2.3.1示例一

首先是我们之前学习c语言时常见的冒泡排序:
 

void bubble_sort(int* arr, size_t sz)
{
	assert(arr);
	int exchange = 0;
	int a = 0;
	for (int i = 0; i < sz; i++)
	{
		for (int j = 0; j < sz - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				a = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = a;
				exchange = 1;
			}
		}
		if (exchange == 0)
			break;
	}
}

       由于定义常值的代码只有一两条(类似于int exchange = 0),所以这里我们只看循环部分即可推出该程序的时间复杂度。

       首先,最理想的情况即是数组本身就为顺序排列的话,那我们的时间复杂度为O(N),当最坏的情况下数组为降序,这时拍的次数最多为1/2(N*N + N),根据上面的渐进表示法我们可以得知,此时的时间复杂度为O(N*N)。所以此程序的时间复杂度为O(N*N)。由此可见我们程序的时间复杂度其实是由最坏的情况所决定的。

下面的例题供大家熟悉这套规则的同时,了解我们之后常见的时间复杂度的计算方式:

2.3.2示例二

void Func(int N)
{
	int count = 0;
	for (int k = 0; k < 2 * N; ++k)
	{
		++count;
	}
	int M = 10;
	while (M--)
	{
		++count;
	}
	printf("%d\n", count);
}

他的执行次数为2N+10,所以我们根据渐进表示法的第二条准则即可得出其时间复杂度为O(N)。

2.3.3示例三

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)。

2.3.4示例四

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

这里程序的执行次数为常数,所以我们的时间复杂度为O(1)。

2.3.5示例五

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

       这里我们的执行次数为logn(以2为底),所以我们的时间复杂度为O(logN);但实际上,我们平时写的时候可以将底数忽略,由于当n趋于正无穷的时候,底数对其的影响就微乎其微了,我们可以通过中学时期学过的换底公式得出这个结论,这里不详细介绍换底证明的步骤,如果有兴趣可以自行下去推导。

三,空间复杂度

3.1定义

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

       2.空间复杂度不是程序占用了多少bytes的空间,因为常规情况每个对象大小差异不会很大,所以空间复杂度算的是变量的个数。

       3.空间复杂度计算规则基本跟实践复杂度类似,也使用大O渐进表示法。

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

       所以我们可以知道这于时间复杂度的计算相差不大,只是把程序执行的次数改变成了程序额外开辟的空间来进行计算。

3.2示例

3.2.1冒泡排序

​
void bubble_sort(int* arr, size_t sz)
{
	assert(arr);
	int exchange = 0;
	int a = 0;
	for (int i = 0; i < sz; i++)
	{
		for (int j = 0; j < sz - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				a = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = a;
				exchange = 1;
			}
		}
		if (exchange == 0)
			break;
	}
}

​

函数栈帧在编译期间已经确定好了,只需要关注函数在运行时额外申请的 空间。 BubbleSort额外申请的空间有 exchange等有限个局部变量,使用了常数个额外空间 因此空间复杂度为O(1)。

3.2.2示例二

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/1925636.html

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

相关文章

【眼疾病识别】图像识别+深度学习技术+人工智能+卷积神经网络算法+计算机课设+Python+TensorFlow

一、项目介绍 眼疾识别系统&#xff0c;使用Python作为主要编程语言进行开发&#xff0c;基于深度学习等技术使用TensorFlow搭建ResNet50卷积神经网络算法&#xff0c;通过对眼疾图片4种数据集进行训练&#xff08;‘白内障’, ‘糖尿病性视网膜病变’, ‘青光眼’, ‘正常’&…

Python+wxauto=微信自动化?

Pythonwxauto微信自动化&#xff1f; 一、wxauto库简介 1.什么是wxauto库 wxauto是一个基于UIAutomation的开源Python微信自动化库。它旨在帮助用户通过编写Python脚本&#xff0c;轻松实现对微信客户端的自动化操作&#xff0c;从而提升效率并满足个性化需求。这一工具的出现&…

SAP PP学习笔记26 - User Status(用户状态)的实例,订单分割中的重要概念 成本收集器,Confirmation(报工)的概述

上面两章讲了生产订单的创建以及生产订单的相关内容。 SAP PP学习笔记24 - 生产订单&#xff08;制造指图&#xff09;的创建_sap 工程外注-CSDN博客 SAP PP学习笔记25 - 生产订单的状态管理(System Status(系统状态)/User Status(用户状态)),物料的可用性检查&#xff0c;生…

语音识别概述

语音识别概述 一.什么是语音&#xff1f; 语音是语言的声学表现形式&#xff0c;是人类自然的交流工具。 图片来源&#xff1a;https://www.shenlanxueyuan.com/course/381 二.语音识别的定义 语音识别&#xff08;Automatic Speech Recognition, ASR 或 Speech to Text, ST…

数字探秘:用神经网络解密MNIST数据集中的数字!

用神经网络解密MNIST数据集中的数字&#xff01; 一. 介绍1.1 MNIST数据集简介1.2 MLP&#xff08;多层感知器&#xff09;模型介绍1.3 目标&#xff1a;使用MLP模型对MNIST数据集中的0-9数字进行分类 二.数据预处理2.1 数据集的获取与加载2.2 数据集的探索性分析&#xff08;E…

编写商品列表和商品编辑和商品新增页面

addvue <template><!-- 传过来的id --> <!-- {{ $route.query.id }} --> <el-formref"FormRef"style"max-width: 600px":model"FormData":rule"rules"status-iconlabel-width"auto"class"demo-r…

【中台】数字中台建设方案(PPT)

数字中台建设要点&#xff1a; 数据采集与整合&#xff1a; 打破企业内部各个业务系统的数据隔阂&#xff0c;通过数据采集和数据交换实现数据的集中管理&#xff0c;形成统一的数据中心&#xff0c;为后续数据价值的挖掘提供基础。 利用自研或第三方ETL&#xff08;Extract, T…

最长下降序列

如何理解这个题目呢,我们可以每个人的分数放到排名上&#xff0c;然后求解最长下降序列即可 #include<bits/stdc.h> using namespace std;int n; const int N (int)1e5 5; int a[N]; int b[N]; int d[N]; int dp[N]; int t;int main() {cin >> t;while (t--) {…

排序——归并排序及排序章节总结

前面的文章中 我们详细介绍了排序的概念&#xff0c;插入排序&#xff0c;交换排序与选择排序&#xff0c;大家可以通过下面的链接再去学习&#xff1a; ​​​​​​排序的概念及插入排序 交换排序 选择排序 这篇文章就详细介绍一下另一种排序算法&#xff1a;归并排序以及…

PE文件(十)重定位表

重定位表的引入 程序加载过程 在win32下&#xff0c;每一个PE文件&#xff08;其可能由多个子PE文件组成&#xff09;在运行时&#xff0c;操作系统会给分配一个独立的4GB虚拟内存&#xff0c;内存地址从0x00000000到0xFFFFFFFF。其中低2G为用户程序空间&#xff0c;高2G为操…

【Linux】进程间通信——消息队列和信号量

目录 消息队列&#xff08;message queue&#xff09; 信号量&#xff08;Semaphore&#xff09; system V版本的进程间通信方式有三种&#xff1a;共享内存&#xff0c;消息队列和信号量。之前我们已经说了共享内存&#xff0c;那么我们来看一下消息队列和信号量以及它们之间…

【鸿蒙学习笔记】位置设置・position・绝对定位

官方文档&#xff1a;位置设置 目录标题 position&#xff1a;绝对定位&#xff0c;确定子组件相对父组件的位置。 position&#xff1a;绝对定位&#xff0c;确定子组件相对父组件的位置。 正→ ↓ Entry Component struct Loc_position {State message: string Hello Wor…

汇编语言程序设计-8-汇编语言快速查阅

8. 汇编语言快速查阅 文章目录 8. 汇编语言快速查阅常用资料寄存器含义标志寄存器的含义Debug的使用汇编语法 本章列出一些需要经常查阅的知识点。 常用资料 参考视频&#xff1a;烟台大学贺利坚老师的网课《汇编语言程序设计系列专题》&#xff0c;或者是B站《汇编语言程序设计…

vue学习day08-v-model详解、sync修饰符、ref和$refs获取dom组件、Vue异步更新和$nextTick

25、v-model详解 &#xff08;1&#xff09;v-model原理 1&#xff09;原理: v-model本质上是一个语法糖&#xff0c;比如&#xff1a;在应用于输入框时&#xff0c;就是value属性与input事件的合写。 2&#xff09;作用 ①数据变&#xff0c;视图变 ②视图变&#xff0c…

【 C++ 】详解 (类和对象) 继承

继承的概念及定义 继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特性的基础上进行扩展&#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类。继承呈现了面向对象 程序设计的层次结构…

【Linux】Linux的账号和用户组

管理员的工作中&#xff0c;相当重要的一环就是【管理账号】。 因为整个系统都是你在管理&#xff0c;并且所有一般用户的账号申请&#xff0c;都必须要通过你的协助才行&#xff0c;所以你就必须要了解一下如何管理好一个服务器主机的账号。 在管理Linux主机的账号时&#xff…

Python应用开发——30天学习Streamlit Python包进行APP的构建(15):优化性能并为应用程序添加状态

Caching and state 优化性能并为应用程序添加状态! Caching 缓存 Streamlit 为数据和全局资源提供了强大的缓存原语。即使从网络加载数据、处理大型数据集或执行昂贵的计算,它们也能让您的应用程序保持高性能。 本页仅包含有关 st.cache_data API 的信息。如需深入了解缓…

AG32 的MCU与FPGA的主频可以达到568MHz吗

Customers: AG32/ AGRV2K 这个芯片主频和定时器最高速度是多少&#xff1f;用户期望 CPLD计时器功能0.1ns以下。 AGM RE: CPLD做不到 0.1ns的速率&#xff0c;这个需要10G以上的时钟。 那AGRV2K最高多少MHz呢&#xff1f; 一般200MHZ比较容易实现。 进一步说明&#xff1…

智慧校园服务监控功能

智慧校园系统中的服务监控功能&#xff0c;扮演着维护整个校园数字化生态系统稳定与高效运作的重要角色。它如同一位全天候的守护者&#xff0c;通过实时跟踪、分析并响应系统各层面的运行状况&#xff0c;确保教学、管理等核心业务流程的顺畅进行。 服务监控功能覆盖了智慧校园…

自动控制——变速积分的PID控制

变速积分的PID控制 PID控制&#xff08;Proportional-Integral-Derivative Control&#xff09;是工业控制中最常用的控制算法之一。标准的PID控制器由比例&#xff08;P&#xff09;、积分&#xff08;I&#xff09;和微分&#xff08;D&#xff09;三个部分组成&#xff0c;…