初识《时间复杂度和空间复杂度》

目录

前言:

关于数据结构与算法

1.什么是数据结构?

2.什么是算法?

3.数据结构和算法的重要性

算法效率是什么?

1.怎样衡量一个算法的好坏呢?

2.算法的复杂度是个什么?

时间复杂度

1.时间复杂度的概念

2.大O的渐进表示法

3.举例说明(动手实践)

例1:

 例2:

例3:

例4:

例5:

例6:

例7:

例8:

总结:

空间复杂度

举例说明

例1

例2

例3 

总结


前言:

从本文开始,我们已经结束了之前对于C语言的初步学习,接下来我们就要运用我们学习过的C语言知识来实现问题的解决,因此我们不得不引入一大类————《数据结构与算法》。

接下来的我们将会进行大量刷题与知识理解,在这里我们一定不能松懈,一定要去动手解决自己不熟悉的部分。

关于数据结构与算法

1.什么是数据结构?

数据结构是指在计算机中组织和存储数据的方式,它是计算机科学的一个基本概念。数据结构涉及到的是数据如何在内存中进行存储和访问,以及对数据进行操作和处理的方法。在计算机科学中,数据结构广泛应用于算法设计和实现,数据库管理系统,编译器和操作系统等领域。常见的数据结构有数组、链表、树、图等。掌握数据结构对于编写高效、优化的程序和解决复杂问题至关重要。

2.什么是算法?

简单来说,算法是一组解决问题的步骤和规则。在计算机科学中,算法是用来解决计算问题的有限指令集合,即一种可用来求解某一问题的明确定义的方法。算法包括准确的定义、输入、输出、有限性、确切性和有效性等特征。在计算机程序设计中,算法通常被用来解决各种问题,如搜索、排序、优化、数据压缩等。算法的设计和实现是计算机科学和编程中非常重要的组成部分。

3.数据结构和算法的重要性

数据结构和算法是计算机科学中非常重要的概念,它们可以帮助我们更高效地解决实际问题。具体来说,以下是数据结构和算法的重要性:

  1. 提高代码质量:使用正确的数据结构和算法可以提高代码的可读性、可维护性,减少代码的复杂度。

  2. 优化程序性能:通过选择合适的数据结构和算法,程序可以更快、更高效地执行。

  3. 解决实际问题:数据结构和算法是解决实际问题的基础,例如搜索、排序、最短路径等问题。

  4. 掌握基本编程技能:学习数据结构和算法是掌握基本编程技能的一部分,对于从事编程相关工作的人员而言是必须的。

  5. 促进思维能力:学习数据结构和算法可以提高我们的逻辑思维能力,培养我们的分析和解决问题的能力。

综上所述,学习数据结构和算法对于计算机科学的学习和实践都非常重要。

算法效率是什么?

1.怎样衡量一个算法的好坏呢?

衡量一个算法的好坏有多种方法,以下是一些常见的:

  1. 时间复杂度:算法执行所需的时间是衡量其好坏的重要因素之一。时间复杂度是指算法执行所需的时间随着输入数据规模增加而增加的速度。一般来说,时间复杂度越低,算法的执行效率就越高。

  2. 空间复杂度:同样是衡量算法好坏的重要因素之一,空间复杂度是指算法执行所需的内存空间随着输入数据规模增加而增加的速度。一般来说,空间复杂度越低,算法的内存利用率越高。

  3. 精度和准确性:算法的输出结果应该与期望的结果一致,并且应该尽可能精确。这是针对特定问题的衡量标准,不同问题需要不同的衡量方式。

  4. 可读性和可维护性:算法代码应该易于理解和修改,并且应该易于维护。代码的可读性和可维护性有助于提高软件的可靠性和可用性。

  5. 可扩展性:算法应该易于扩展,以便在需要时可以轻松地进行修改和更新。可扩展性是在需求变化时重要的因素。

综上所述,衡量算法的好坏需要综合考虑多个因素,根据实际情况选择相应的衡量标准。

2.算法的复杂度是个什么?

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

时间复杂度主要衡量一个算法的运行快慢,而空间复杂度主要衡量一个算法运行所需要的额外空间。在计算 机发展的早期,计算机的存储容量很小。所以对空间复杂度很是在乎。

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

时间复杂度

1.时间复杂度的概念

在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。一 个算法执行所耗费的时间,从理论上说,是不能算出来的,只有你把你的程序放在机器上跑起来,才能知 道。但是我们需要每个算法都上机测试吗?是可以都上机测试,但是这很麻烦,所以才有了时间复杂度这个 分析方式。一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法的时间复杂度。

即:找到某条基本语句与问题规模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;}printf("%d\n", count);
}

 现在先来尝试计算机算以上代码的时间复杂度吧。

 

实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么这 里我们使用大O的渐进表示法。 

2.大O的渐进表示法

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

推导大O阶方法: 1、用常数1取代运行时间中的所有加法常数。

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

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

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

O(N^2)

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

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

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

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

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

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

最好情况:1次找到

最坏情况:N次找到

平均情况:N/2次找到

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

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

这里的时间复杂度应当为O(2*N + M)

但是由大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);
}

通过我上面所讲的,这里不难看出时间复杂度应当为O(N+M),即

O(N)

 

例3:

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

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

 O(1)

 

例4:

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

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

O(N)

例5:

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

此例为冒泡排序,通过之前对数组的学习我们可以知道冒泡排序是效率最低,时间复杂度最高的算法,因为它要走n趟,并且在每一趟又要完遍历完n - i - 1个元素。

如果忘记了冒泡排序的实现,可以参考我之前写的blog

关于数组名-CSDN博客

如果你很熟练的话,通过我上述的描述你就知道该时间复杂度为O(N^2)了。

但是对于刚开始来学习的呢,有以下解释:

实例5基本操作执行最好N次,最坏执行了(N*(N+1))/2次,通过推导大O阶方法+时间复杂度一般看最坏,时间复杂度为 O(N^2) 

 最坏的情况是怎么算出来的?

这就要回顾我们在高中学习到对等差数列的求和公式。

即:

(首项 + 尾项)*(项数)/ 2

什么意思呢?

最坏的情况莫过于冒牌排序一个逆序数组,因为他对每个数字都进行了排序。

如此我们可以简化为:

 

将各个长度相加,不就是等差求和了吗,如此一来我们就理解了为什么是要等差求和。

所以最后的答案就是

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

此例为二分查找的代码,答案为O(logN)

对这道题我们可以用折纸再展开的方式来理解。

在这里我们先从代码的角度先讲解一下为什么是logN。

首先,我们要分析最坏的情况。

最坏的情况莫过于在数组经历二分查找后的最后一个元素为我们要查找的数。

所以我们就有以下的图:

 所以最终的答案是

O(logN)

我们在这里对2会进行省略。

虽然二分查找的时间复杂度很低,但是我们使用该算法之前要对其进行排序。

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

 对于斐波那契数列的递归实现,其实和细胞分裂很像,一生二,二生四,四生八等等等,这种以指数形式增加的。

所以通过思想来看,不难看出时间复杂度为

O(2^N)

总结:

以上就是关于时间复杂度的一些例题,仅通过这些无法较好的彻底学会使用时间复杂度,后续我们在刷题的同时,也会适当的对时间复杂度进行讲解。 

要记住,首先看思路再看代码!

空间复杂度

空间复杂度也是一个数学表达式,是对一个算法在运行过程中临时占用存储空间大小的量度 。 空间复杂度不是程序占用了多少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

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)

总结

时间复杂度是算法执行所需时间的度量,通常使用大 O 符号表示。它表示当输入规模变大时,算法执行时间增长的快慢程度。时间复杂度越小,算法执行速度越快。

空间复杂度是算法执行所需内存的度量,也通常使用大 O 符号表示。它表示当输入规模变大时,算法所需内存增长的快慢程度。空间复杂度越小,算法所需内存越少。

在设计算法时,需要充分考虑时间和空间复杂度。如果一个算法时间复杂度较小,但空间复杂度过高,可能会导致程序在执行时占用过多的内存而造成程序崩溃。因此,需要在时间复杂度和空间复杂度之间取得一个平衡,使得算法在执行时既能保持较快的速度,又能占用尽可能少的内存。

 这部分内容会比较抽象,但是我们需要多多练习,数据结构和算法的内容是这样的抽象的,所以我们更不应该放弃。

这些部分是人发现的算法,既然是人那么我也可以,现在想不明白不代表明天不明白,只要肯坚持就不会有想不出来的。

记住,

坐而言不如起而行!

Action speak louder than words!

以下是这篇文字所需要的代码:

Time_complexity_and_Space_complexity_CSDN/Time_complexity_and_Space_complexity_CSDN/test_10_27.c · 无双/Data structures amd algorithms - Gitee.com

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

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

相关文章

微服务技术导学

文章目录 微服务结构认识微服务技术栈 微服务结构 技术&#xff1a; 解决异常定位&#xff1a; 持续集成&#xff0c;解决自动化的部署&#xff1a; 总结如下&#xff1a; 认识微服务 微服务演变&#xff1a; 技术栈 SpringCloud与SpringBoot版本对应关系

VS2022 C# 读取 excel 2023年

今天是2023年6月26日&#xff0c;我有一个excel表要读数据&#xff0c;然后放到winform程序来处理&#xff0c;网上的资料太旧&#xff0c;很多用不起来&#xff0c;试了一个可以使用&#xff0c;记录一下&#xff1a; 一、excel文件后缀需要小写。 二、用VS2022建一个winform…

Java练习题2020 -1

统计1到N的整数中&#xff0c;被A除余A-1的偶数的个数 输入说明&#xff1a;整数 N(N<10000), A, (A 输出说明&#xff1a;符合条件的数的个数 输入样例&#xff1a;10 3 输出样例&#xff1a;2 (说明&#xff1a;样例中符合条件的2个数是 2、8) import java.util.Scanner;p…

Web:探索 SpreadJS强大的在线电子表格库

1、概述 SpreadJS 是葡萄城结合 40 余年专业控件技术和在电子表格应用领域的经验而推出的纯前端表格控件,基于 HTML5,兼容 450 多种 Excel 公式,具备“高性能、跨平台、与 Excel 高度兼容”的产品特性,SpreadJS 在界面和功能上与 Excel 高度类似,但又不局限于 Excel,而是…

【电路笔记】-电路中的复数与相量(Phasor)

电路中的复数与相量(Phasor) 文章目录 电路中的复数与相量(Phasor)1、概述2、复数定义3、复数计算规则4、电子领域的复数5、总结 复数是一种重要的数学工具&#xff0c;广泛应用于包括电子学在内的许多物理领域。 这个概念可能看起来很奇怪&#xff0c;但它们的操作很简单&…

【Docker从入门到入土 6】Consul详解+Docker https安全认证(附证书申请方式)

Part 6 一、服务注册与发现的概念1.1 cmp问题1.2 服务注册与发现 二、Consul ----- 服务自动发现和注册2.1 简介2.2 为什么要用consul&#xff1f;2.3 consul的架构2.3 Consul-template 三、consul架构部署3.1 Consul服务器Step1 建立 Consul 服务Step2 查看集群信息Step3 通过…

axios封装以及详细用法

文章目录 axios用法(这里没有封装&#xff0c;下面有封装好的get&#xff0c;post方法&#xff0c;在axios封装里面)get &#xff0c;delete方法post&#xff0c;put方法 axios具体封装axios 具体参数配置 axios用法(这里没有封装&#xff0c;下面有封装好的get&#xff0c;pos…

项目中拖拽元素,可以使用html的draggable属性,当然也可以用第三方插件interact

项目中拖拽元素&#xff0c;可以使用html的draggable属性&#xff0c;当然也可以用第三方插件interact 一、安装二、引用三、使用 一、安装 npm install interactjs二、引用 import interact from interactjs三、使用 <div class"drag_box"> &…

基于android的 rk3399 同时支持多个USB摄像头

基于android的 rk3399 同时支持多个USB摄像头 一、前文二、CameraHal_Module.h三、CameraHal_Module.cpp四、编译&烧录Image五、App验证 一、前文 Android系统默认支持2个摄像头&#xff0c;一个前置摄像头&#xff0c;一个后置摄像头 需要支持数量更多的摄像头&#xff0…

selenium工作原理和反爬分析

一、 Selenium Selenium是最广泛使用的开源Web UI(用户界面)自动化测试套件之一&#xff0c;支持并行测试执行。Selenium通过使用特定于每种语言的驱动程序支持各种编程语言。Selenium支持的语言包括C#&#xff0c;Java&#xff0c;Perl&#xff0c;PHP&#xff0c;Python和Ru…

如何查看多开的逍遥模拟器的adb连接端口号

逍遥模拟器默认端口号为&#xff1a;21503。 不过&#xff0c;使用多开器多开的时候&#xff0c;端口就不一定是21503了。 如何查看&#xff1f; 进入G:\xiaoyao\Microvirt\MEmu\MemuHyperv VMs路径中 每多开一个模拟器&#xff0c;就会多出一个文件夹。 进入你要查找端口号…

2023年MathorCup高校数学建模挑战赛大数据挑战赛赛题浅析

比赛时长为期7天的妈杯大数据挑战赛如期开赛&#xff0c;为了帮助大家更好的选题&#xff0c;首先给大家带来赛题浅析&#xff0c;为了方便大家更好的选题。 赛道 A&#xff1a;基于计算机视觉的坑洼道路检测和识别 A题&#xff0c;图像处理类题目。这种题目的难度数模独一档…

SpringAOP源码解析之advice执行顺序(三)

上一章我们分析了Aspect中advice的排序为Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class&#xff0c;然后advice真正的执行顺序是什么&#xff1f;多个Aspect之间的执行顺序又是什么&#xff1f;就是我们本章探讨的问题。 准备工作 既…

基于Python Django 的微博舆论、微博情感分析可视化系统(V2.0)

文章目录 1 简介2 意义3 技术栈Django 4 效果图微博首页情感分析关键词分析热门评论舆情预测 5 推荐阅读 1 简介 基于Python的微博舆论分析&#xff0c;微博情感分析可视化系统&#xff0c;项目后端分爬虫模块、数据分析模块、数据存储模块、业务逻辑模块组成。 Python基于微博…

第八节——Vue渲染列表+key作用

一、列表渲染 vue中使用v-for指令进行列表 <template><div><!-- item 代表 当前循环的每一项 --><!-- index 代表 当前循环的下标--><!-- 注意&#xff1a;必须要加key--><div v-for"(item, index) in arr" :key"index"…

UE5 Blueprint发送http请求

一、下载插件HttpBlueprint、Json Blueprint Utilities两个插件是互相依赖的&#xff0c;启用&#xff0c;重启项目 目前两个是Beta的状态&#xff0c;如果你使用的平台支持就可以使用&#xff0c;我们的项目因为需要取Header的值&#xff0c;所有没法使用这两个插件&#xff0…

DBeaver安装与使用教程(超详细安装与使用教程),好用免费的数据库管理工具

DBeaver安装步骤 资源下载&#xff1a; https://download.csdn.net/download/qq_37181642/88479235 官网地址&#xff1a; https://dbeaver.io/ 安装dbeaver 点击上图.exe安装工具&#xff0c;安装完成后不要打开 。 windows配置hosts 在hosts文件中加入&#xff1a; 127.0.0…

基于SSM民宿预订及个性化服务系统-计算机毕设 附源码 04846

SSM民宿预订及个性化服务系统 摘 要 伴随着国内旅游经济的迅猛发展民宿住宿行在国内也迎来了前所未有的发展机遇。传统的旅游模式已难以满足游客日益多元化的需求&#xff0c;随着人们外出度假的时间越来越长&#xff0c;导致人们在住宿的选择上更加追求舒适、个性化的住宿体验…

Kafka - 3.x 副本不完全指北

文章目录 kafka 副本的基本信息Leader选举过程Kafka Controllerkafka 分区副本Leader的选举流程实际演示① 查看first的详细信息&#xff0c;注意观察副本分布情况② 停掉hadoop103上的kafka进程③ 再次查看first的相信信息&#xff0c;观察副本分布④ 处理分区leader分布不均匀…

Spring Cloud之微服务

目录 微服务 微服务架构 微服务架构与单体架构 特点 框架 总结 SpringCloud 常用组件 与SpringBoot关系 版本 微服务 微服务&#xff1a;从字面上理解即&#xff1a;微小的服务&#xff1b; 微小&#xff1a;微服务体积小&#xff0c;复杂度低&#xff0c;一个微服…