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

news2025/1/18 9:56:57

目录

🚀 0.前言

🚀 1.为何会有时间复杂度和空间复杂度的概念

🚀 2.时间复杂度

2.1初步时间复杂度

2.2大O表示法

2.2.1.O(N*N)

2.2.2.O(N)

2.2.3.O(1)

2.3最坏情况?

2.3.1O(N*N)

2.4递归 

2.4.1O(N)

2.4.2O(2^N)

🚀 3.空间复杂度

3.1O(1)

3.2 O(N)

🚀4.结束语


🚀 0.前言

        言C之言,聊C之识,以C会友,共向远方。各位CSDN的各位你们好啊,这里是持续分享数据结构知识的小赵同学,今天要分享的数据结构知识是时间复杂度和空间复杂度,在这一章,小赵将会向大家展开聊聊何为时间复杂度,何为空间复杂度。✊

🚀 1.为何会有时间复杂度和空间复杂度的概念

        其实为何会有这两个概念呢?其实很简单,就像我们人类的工作吧,老板在挑选工作的时候总会挑选那些工作效率高(即用时少),给工资低的人,来作为自己的员工。因为挑选这样的人做自己的员工可以让自己的利益最大化。而我们的计算机在写程序的时候也一样,我们要让自己的程序最好,那么就要降低它的工作时间和占用空间的大小。由此引申出两个概念时间复杂度和空间复杂度。而这两个东西又该如何去看呢?别急小赵下面一一介绍。

🚀 2.时间复杂度

2.1初步时间复杂度

        什么叫时间复杂度呢?其实就是程序运行次数的极限。那固定的次数有极限吗?答案当然是没有啦,所以我们的所有固定次数的程序是最容易看出时间复杂度的。虽然我们在学的时候往往会将它们归向程序的时间复杂度较低的一列,但如果运行次数过多,那它的时间复杂度也是很恐怖的,那什么时候就很多了呢?请看下面的代码:

for (int i = 1; i <= 10000000000; i++)
{
	for (int j = 1; j <= 10000000000; j++)
		printf("%d", 1);
}

       大家只要稍微算一下这个代码的运行次数,就会发现这个代码的运行次数无比庞大,而这种代码也往往是我们不能用的,因为其的运行次数太多,尽管没有n但其的时间复杂度也惊为天人。

好了聊完了这个的时间复杂度,下面我们进入正题,来看看我们带n(未知数)的时间复杂度该如何计算和表示。 

2.2大O表示法

        在上面小赵举了一个非常恐怖的例子,明明次数是固定的,但好像程序的运行次数还是如此恐怖,那究竟是原因导致了它呢?其实大多数小伙伴已经看出其中的玄妙了,这个代码的运行是两层循环次数的乘积。同样的代码各位可以看看这个代码:

2.2.1.O(N*N)

for (int i = 0; i < N ; ++ i)
{
    for (int j = 0; j < N ; ++ j) 
    { 
      ++count;
    }
}

各位如果去算它的运行次数,就会发现它是N*N次的运行次数,这样的运行次数是很恐怖,那我们该如何记录它呢,于是我们就发明了大O表示法。即O((里面是运行了多少次))。这里我们的程序运行了N*N次,用大O表示法就是O(N*N),像这一类的算法我们一般是不用的,因为其的运行次数太多,时间复杂度太高。如果我们用这个来做程序的话,那个程序往往会很慢。

好了有了这个例子我们就可以举一反三再看看别的程序的时间复杂度了。

2.2.2.O(N)

for (int k = 0; k < 2 * N ; ++ k)
 {
     ++count;
 }

有了前面的例子相信有不少小伙伴会一个说出这个代码的时间复杂度是O(N),当然也有小伙伴会说是O(2N) ,那这里的答案是什么呢?答案是O(N),为什么呢?其实一般的解释是要省略其中的数字,这里小赵给大家一个解释吧。就像你把N取无穷一样,你会看得起你面前的二吗?答案应该大多数都是不会,那无穷会看得起谁呢?答案就是无穷,只有两个地位差不多或者相似的人才能谈得上话。不然都是空谈。

2.2.3.O(1)

for (int k = 0; k < 100; ++ k)
 {
     ++count;
 }

那这种没有N的呢?这里我们特殊地给了他们一个位置,我们叫它O(1),虽然在定义上这种程序的运行速度应该很快,但实际上很多时候都会出现诈尸的情况,如我举得第一个例子,其的运行次数太多,让人难以接受,所以各位在做题时也要极为小心,避免写出时间复杂度极高的程序,让程序过不了。

2.3最坏情况?

2.3.1O(N*N)

 好了开胃菜吃多了,下面也该上点正菜,就用我们学过的冒泡排序举例子吧

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*N),但实际上很多人并不理解为什么是这个答案。那么是这个答案的原因是什么呢?其实是因为我们在看计算机的程序运行次数的时候,往往考虑的其实是他的最差情况,那么这样也就好理解这个答案,按我们去算这个最坏就是每个数字都要换,用数学方法算出来就是(N*(N+1)/2次,然后我们去掉数字,就是N*N,所以这题的结果就是O(N*N)。而这样的时间复杂度其实也决定了冒泡排序不是我们主流的排序方法,因为其的时间复杂度太大。

2.3.1O(log N)

看完了冒泡排序,我们再来看看我们的二分查找。

int BinarySearch(int* a, int n, int x)
{
  assert(a);
  int begin = 0;
  int end = n-1;
 while (begin <= end)
 {
    int mid = begin + ((end-begin)>>1);
    if (a[mid] < x)
       begin = mid+1;
    else if (a[mid] > x)
       end = mid-1;
    else
       return mid;
}
    return -1;
}

二分查找的最坏情况是logN次所以其的时间复杂度是O(logN),这个时间复杂度是很小的,二分查找也是我们在查找数字常用的算法,但是其必须要求数组是已经排好的,这让他有了局限性。

2.4递归 

好了看惯了循环,给各位换换胃口,我们看看递归的时间复杂度该如何看:

2.4.1O(N)

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

这个代码我们只要一直向下迭代就会发现最后其实是运行了N次,那么其的时间复杂度就是 O(N);

2.4.2O(2^N)

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

这个递归就相对比较复杂了,也是我们后面二叉树时候将要面对的难题,这里我们我们用递归展开图神器解决

我们对这个代码进行估算,最后会发现我们这个代码最多运行2的N次方-1,那么其的时间复杂度就是O(2^N)。

好了时间复杂度到这里就结束了,相信各位已经能够熟练掌握了,为自己再掌握一个知识点欢呼

🚀 3.空间复杂度

了解了时间复杂度,其实空间复杂度就很简单了,因为这两个都是用的大O表达式,而这里就是吧运行次数改成你这个程序在运行时开辟的额外空间。

直接举例子吧。

3.1O(1)

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

以冒泡排序举例,x,我们就定为O(1)(或者开辟几个固定空间跟前面一样)。

3.2 O(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;
}

在这个程序中一共开辟了N+1个空间,所以空间复杂度为O(N); 

🚀4.结束语

 好了小赵今天的分享就到这里了,如果大家有什么不明白的地方可以在小赵的下方留言哦,同时如果小赵有什么地方不对也希望得到大家的指点,谢谢各位家人们的支持。你们的支持是小赵创作的动力,加油。

如果觉得文章对你有帮助的话,还请点赞,关注,收藏支持小赵,如有不足还请指点,小赵及时改正,感谢大家支持!!!

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

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

相关文章

【Qt】error LNK2001: 无法解析的外部符号

参考&#xff1a;Qt/VS LNK2019/LNK2001&#xff1a;无法解析的外部符号_qt lnk2001无法解析的外部符号-CSDN博客 微软官方报错文档-链接器工具错误 LNK2019 __declspec error LNK2001: 无法解析的外部符号 "__declspec(dllimport) 原因 以这种为前缀的基本上跟库相关…

微信小程序:11.本地生活小程序制作

开发工具&#xff1a; 微信开发者工具apifox进行创先Mock 项目初始化 新建小程序项目输入ID选择不使用云开发&#xff0c;js传统模版在project.private.config中setting配置项中配置checkinalidKey&#xff1a;false 梳理项目结构 因为该项目有三个tabbar所以我们要创建三…

点击消除

点击消除 描述&#xff1a; 对一个字符串&#xff0c;每次“点击”&#xff0c;可以把字符串中相邻两个 相同字母消除。 例如&#xff0c;字符串"abbc"点击后可以生成"ac"。 但相同而不相邻、不相同的相邻字母都是不可以被消除的。 如果想把字符串变得…

比亚迪24届春招Offer面经

本文介绍2024届春招中&#xff0c;比亚迪的高级底盘工程师岗位1场面试的基本情况、提问问题等。 2024年04月投递了比亚迪的系统开发类、 技术研发类、 技术研究类岗位&#xff0c;面试结束后分配至高级底盘工程师岗位&#xff1b;面试前未确定部门&#xff0c;面试结束后分配至…

关于OSPF报文学习

目录 一.OSPF学习补充 &#xff08;1&#xff09;OSPF报文头部 &#xff08;2&#xff09;ospf建立邻居关系 1.Hello报文——建立邻居关系 2.hello报文头部 &#xff08;3&#xff09;OSPF建立邻接关系 1.发送DD报文 2.DD报文头部 &#xff08;4&#xff09;关于DR,BD…

Blender点操作

顶点操作即一般的“布线”操作 1.顶点移动 -先切到顶点模式 -移动&#xff0c;G 或 G X/Y/Z -旋转&#xff0c;R 同上 -缩放&#xff0c;S 同上 2.顶点滑移&#xff0c;用于微调顶点的位置 快捷键&#xff1a;Shift V&#xff0c;G G 3.顶点删除 -选中一个顶点 -按…

【算法】人工蜂群算法,解决多目标车间调度问题,柔性车间调度问题

文章目录 复现论文什么是柔性作业车间调度问题&#xff1f;数据处理ABC算法编码解码种群初始化雇佣蜂操作IPOX交叉多点交叉 观察蜂操作侦察蜂操作算法流程 结果程序截图问询、帮助 复现论文 什么是柔性作业车间调度问题&#xff1f; 也叫多目标车间调度问题。 柔性作业车间调…

构建NodeJS库--前端项目的打包发布

1. 前言 学习如何打包发布前端项目&#xff0c;需要学习以下相关知识&#xff1a; package.json 如何初始化配置&#xff0c;以及学习npm配置项&#xff1b; 模块类型type配置&#xff0c; 这是nodejs的package.json的配置main 入口文件的配置 webpack 是一个用于现代 JavaSc…

golang反射

go反射 反射基本介绍应用场景基本使用结构体注意练习最佳实践遍历结构体的方法&#xff0c;调用接头体的方法&#xff0c;获取结构体的标签 反射 基本介绍 反射可以在运行时动态获取变量的各种信息&#xff0c;比如变量的类型(type)、类别(kind)如果是结构体变量&#xff0c;…

Java应用开发必备:使用 easy-captcha 组件生成验证码的详细介绍

一、前言 最近系统开发在优化验证码的相关功能&#xff0c;第一反应就是有没有开源的第三方组件可以使用呢。 在一番寻觅以后&#xff0c;还真发现一个好用的第三方验证码组件Easy-captcha。Easy-captcha是一个开源的Java库&#xff0c;用于生成和验证验证码&#xff0c;它的…

RGB灯珠的控制-单片机通用模板

RGB灯珠的控制-单片机通用模板 一、RGB控制的原理二、RGB.c的实现三、RGB.h的实现四、color色彩空间变换以及控制渐变一、RGB控制的原理 ①通过IO发送脉冲识别0/1编码,组合24Bit的RGB数据,从而控制RGB;②每个RGB灯珠通过DIN、DOU进行级联起来;③通过HSV色彩转换成RGB从而控…

Tomcat架构设计精髓分析-Connector高内聚低耦合设计

优秀的模块化设计通常都会采用高内聚、低耦合 高内聚是指相关度比较高的功能要尽可能集中&#xff0c;不要分散。低耦合是指两个相关的模块要尽可能减少依赖的部分和降低依赖的程序&#xff0c;不要让两个模块产中强依赖。 Tomca连接器需要实现的功能: 监听网络端口 接受网络…

手撕netty源码(一)- NioEventLoopGroup

文章目录 前言一、NIO 与 netty二、NioEventLoopGroup 对象的创建过程2.1 创建流程图2.2 EventExecutorChooser 的创建 前言 processOn文档跳转 本文是手撕netty源码系列的开篇文章&#xff0c;会先介绍一下netty对NIO关键代码的封装位置&#xff0c;主要介绍 NioEventLoopGro…

使用PyCharm开发工具创建工程

一. 简介 前面文章实现了开发 python程序使用的 开发工具PyCharm&#xff0c;本文来学习使用 PyCharm开发工具创建一个 python工程。 二. 使用PyCharm开发工具创建工程 1. 首先&#xff0c;打开 PyCharm开发工具&#xff0c;打开 "New project" 选项&#xff1a; …

hive启动beeline报错

问题一在zpark启动集群报错 出现上面的问题执行以下代码 chmod 777 /opt/apps/hadoop-3.2.1/logs 问题二启动beeline报错 执行 cd /opt/apps/hadoop-3.2.1 bin/hadoop dfsadmin -safemode leave 问题三执行查询语句报错 执行 set hive.exec.mode.local.autotrue;

java接口加密解密

这里写目录标题 controller加解密工具类加密&#xff08;本质是对ResponseBody加密&#xff09;解密&#xff08;本质是对RequestBody传参解密&#xff09;注解 controller Controller public class PathVariableController {GetMapping(value "/test")ResponseBod…

Redis缓存问题:穿透,击穿,雪崩等

Redis缓存问题:穿透,击穿,雪崩等 在高并发场景下,数据库往往是最薄弱的环节,我们通常选择使用redis来进行缓存,以起到缓冲作用,来降低数据库的压力,但是一旦缓存出现问题,也会导致数据库瞬间压力过大甚至崩溃,从而导致整个系统崩溃.今天就聊聊常见的redis缓存问题. 缓存击穿 …

相关分析方法

目录 1.什么是相关分析方法 2.相关系数 3.常见的相关分析方法 3.1.皮尔逊相关系数 3.2.斯皮尔曼等级相关 ​​​​​​​3.3.肯德尔等级相关 ​​​​​​​3.4.其它 4.应用 5.注意事项 6.结语 1.什么是相关分析方法 相关分析是数据分析中的一种统计方法&#xff0c…

[C++基础学习]----02-C++运算符详解

前言 C中的运算符用于执行各种数学或逻辑运算。下面是一些常见的C运算符及其详细说明&#xff1a;下面详细解释一些常见的C运算符类型&#xff0c;包括其原理和使用方法。 正文 01-运算符简介 算术运算符&#xff1a; a、加法运算符&#xff08;&#xff09;&#xff1a;对两个…

RabbitMQ(高级)笔记

一、生产者可靠性 &#xff08;1&#xff09;生产者重连&#xff08;不建议使用&#xff09; logging:pattern:dateformat: MM-dd HH:mm:ss:SSSspring:rabbitmq:virtual-host: /hamllport: 5672host: 192.168.92.136username: hmallpassword: 123listener:simple:prefetch: 1c…