当前位置: 首页 > news >正文

算法基础——复杂度

前言

       算法是解决问题的一系列操作的集合。著名的计算机科学家Niklaus Wirth曾提出:算法+数据结构=程序,由此可见算法在编程中的重要地位。本篇主要讨论算法性能好坏的标准之一——复杂度。 


 1 复杂度概述

1.1 什么是复杂度

       本文所讨论的复杂度是指通过事先估算法计算出的用来衡量算法效率的值。因此并不是说代码的长度越长复杂度就越高,或者代码中的数据越多复杂度就越高。

1.2 为什么会有复杂度

       关于复杂度的产生,我们通过下图的问题来引入。假设现在有一个人要从A地前往E地,那么他共有ABE、ADE、ABCE三种路径可以选择,但是我们可以看出,ABE的路程是最短的(假设图中距离与实际距离成比例),经过的地区也是最少的,相较于其它两条路径,ABE的优势非常明显。

       算法是用来解决问题的操作步骤的集合,而我们解决同一个问题可能会如上例一样,有多种路径,这时我们需要一个标准来评判每条路径的好坏。这样一来,算法的复杂度就被提出了。

1.3 复杂度分类

       算法的复杂度分为时间复杂度空间复杂度两种。

       时间复杂度用来衡量算法消耗时间的多少,空间复杂度用来衡量算法所需开辟新空间的多少。

2 时间复杂度

2.1 什么是时间复杂度

       首先我们要明白,程序运行的绝对时间并不是衡量算法效率的标准。举个不太恰当的例子,使用“ENIAC”计算机(世界上第一台电子数字式计算机)与“天河一号”超级计算机执行相同的算法(死循环除外),它们的绝对时间必然有所不同。

       从中我们得出,当我们评判一个算法的好坏时,不能附带有硬件条件的影响,而应关注算法本身。算法的执行时间的长度可以由每条语句的执行时间乘以该语句的执行次数,再加和得到。而每条语句的单次执行时间对现代计算机来说几乎可以忽略不计,那么对于一个程序的执行时间影响最大的因素就是单条语句的执行次数了。

       因此,时间复杂度主要是用来渐进表示执行次数最多的单条语句的执行次数。

2.2 时间复杂度的计算 

       时间复杂度通常用"O"表示。对于任意输入量n(这里的输入量不一定是数字,也可能为数组或结构变量等,根据具体情况而定),算法的时间复杂度可记作"O(f(n))",其中f(n)为n的函数,表示算法中的语句的执行次数。但是我们通常会使用渐进表示法来表示时间复杂度,即取f(n)中次数最高的项来表示(当n足够大时,最高次项对整个数值的影响最大)。

       如果仅仅通过这些文字来理解时间复杂度可能较为抽象,我们通过几个简单的例子来理解一下。

int main()
{int a;int i;for(i=0;i<10;i++)a=i;return 0;
}

       我们来看这段代码,这其中代码执行的总次数(即执行的语句数量)为13,为一个常数,我们计这段代码的时间复杂度为"O(1)"。

       这可能与大家的理解有些偏差,明明执行次数为13,为什么不计作"O(13)"呢?我们来观察这段代码,由于这段代码的输入量n对程序的运行次数不会产生影响,那么无论输入量n的大小为多少,这段代码的执行次数都是13。当输入量n趋向于无穷大时,执行次数13与1的区别并不大,可以忽略不计。为方便起见,将这些执行次数为常数的算法的时间复杂度计为"O(1)"。

       也就是说,无论算法的语句执行次数为10,20,30还是一亿,十亿,一百亿,只要它是常数,那么当输入量n趋向于无穷大时,这些常数均可忽略不计,则时间复杂度计为"O(1)"。

int main()
{int a;int n;int i;scanf("%d",&n);for(i=0;i<n;i++)a=i;return 0;
}

       我们再来看这段代码,这段代码与之前的代码相比的不同之处在于其有一个输入量n,并且输入量n会对代码的执行次数产生影响,例如,当输入2时,代码执行次数为7;输入量为10时,代码执行次数为15。可以推出,这段代码的执行次数与输入量n的关系为f(n)=n+5。

在这个关系中,当n趋向于无穷大时,5这个常量可忽略不计,因此我们将这个算法的时间复杂度计为"O(n)"。

       通过对上面两段代码的分析,我们可以总结出一些规律,对比可以发现,影响时间复杂度的主要因素就是循环语句的循环次数与输入量n的关系。在第二段代码中,输入量为n时,循环语句执行n次,则时间复杂度为"O(n)"。

int main()
{int i,j,n;scanf("%d",&n);for(i=0;i<n;i++){for(j=0;j<n;j++){printf("%d ",i*j);}}while(i--){j--;}return 0;
}

       我们继续来看,这段代码中存在嵌套循环语句,当输入量为n时,对于任意一次外层循环,内层循环都进行n次。而外层循环也进行n次,因此总共可认为进行n*n次,即n^2。

       除此之外,这段代码中还存在另一段while循环语句,不难得出循环进行n次,因此这段代码执行的总次数可以计为n^2+n+2。当输入量n趋向于无穷大时,相对于n^2,n+2的值对总次数的影响并不大,可以忽略不计。

       因此,这段代码的时间复杂度计为"O(n^2)"。

2.3 一些经典算法的时间复杂度分析

2.3.1 冒泡排序

      冒泡排序是一种简单的交换排序,通过比较相邻两个元素的大小,若它们的大小顺序与所需顺序不同,则交换这两个元素。这里先不讨论冒泡排序的原理,直接来分析代码。

void BubbleSort(int* a,int sz)
{int i,j;for(i=0;i<sz-1;i++)  //排序次数{for(j=0;j<sz-i-1;j++)  //比较次数{if(arr[j]<arr[j+1])  //判断相邻两数据大小{int tmp = arr[j];arr[j] = arr[j+1];arr[j+1] = tmp;}}}
}

      上面为一段最简单的冒泡排序算法,其中参数a为所需排序的数组的地址,sz为所需排序的元素个数,当给定数组大小为n时,该算法的循环总共进行[(n-1)+(n-2)+...+1]次,化简可得(n^2-n)/2次,因此该算法的时间复杂度计为"O(n^2)"。

2.3.2 二分查找 

      二分查找是一种非常高效的查找算法,可以在一串有序数据中快速查找出所需数据。 

int BinarySearch(int* a,int sz,int x)
{int left=0,right = sz-1;while(left<=right){int mid = (left+right)/2;  //取中间值if(a[mid] == x)   return mid;    //找到与x相等的元素,返回下标else if(x > a[mid])left = mid;   //中间值偏小elseright = mid;  //中间值偏大}return -1;  //查找失败
}

       二分查找算法的最好情况是第一次就找到目标值,此时时间复杂度为"O(1)"。但是我们评判一个算法的好坏不可能凭其处理问题的最好情况时的复杂度作为参考,这是没有意义的。一般来讲,我们会以算法的处理最坏情况的时间复杂度作为该算法的时间复杂度。

      在最坏的情况下,在整个数组中无法找到目标元素。由于二分查找每次取中间值即可排除一半的元素,因此可得当输入量为n时,二分查找总共需要进行大约为以二为底n的对数次,当对数的底数为2时,在表示算法的时间复杂度时,可计为"O(logn)"。

      因此,二分查找的时间复杂度为"O(logn)"。

3 空间复杂度 

3.1 什么是空间复杂度

       我们知道,程序运行时需要调用内存空间,而算法作为程序的一部分,同样也需要调用空间。

       而空间复杂度就是衡量一个算法执行所需调用空间的大小的标准。

       在很多情况下,在评判算法的性能好坏时,空间复杂度的参考权重比时间复杂度要低得多,因此有些算法可能会采取牺牲空间复杂度的方式来换取更低的时间复杂度。但这并不代表空间复杂度不重要。

3.2 空间复杂度的计算 

       空间复杂度的计算和时间复杂度的计算较为相似,在理解了时间复杂度的计算规则后,理解空间复杂度的计算应该会比较轻松。我们还是通过例子来分析。

int main()
{int a;return 0;
}
上面这段代码可以说非常简单了,总共开辟了两块内存空间,一块用来调用main函数,另一块存储变量a。由于开辟的空间大小为常数,因此该段代码的空间复杂度为"O(1)"。
int* copy(int* a,int sz)
{int* ret = (int*)malloc(sizeof(int)*sz);return ret;
}

       这是一个复制函数,用来将给定的数组复制。在这个函数中,当给定数组的大小为n时,该函数会开辟一个大小为n的空间用来复制数组,因此其空间复杂度为"O(n)"。


结束语 

       了解复杂度是学习算法的基础,它让我们明白如何判断一个算法的好坏。学会判断复杂度后,我们将会知道如何优化算法,并学会在不同情景下使用最合适的算法。

       以上就是我对复杂度的理解了,如内容有误欢迎各位大佬指正。

相关文章:

算法基础——复杂度

前言 算法是解决问题的一系列操作的集合。著名的计算机科学家Niklaus Wirth曾提出&#xff1a;算法数据结构程序&#xff0c;由此可见算法在编程中的重要地位。本篇主要讨论算法性能好坏的标准之一——复杂度。 1 复杂度概述 1.1 什么是复杂度 本文所讨论的复杂度是指通过事先…...

基类与派生类对象的关系 派生类的构造函数

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C &#x1f525;座右铭&#xff1a;“不要等到什么都没有了&#xff0c;才下…...

【算法】生成分布式 ID 的雪花算法

ID 是数据的唯一、不变且不重复的标识&#xff0c;在查询数据库的数据时必须通过 ID 查询&#xff0c;在分布式环境下生成全局唯一的 ID 是一个重要问题。 雪花算法&#xff08;snowflake&#xff09;是一种生成分布式环境下全局唯一 ID 的算法&#xff0c;该算法由 Twitter 发…...

Linux系统编程 - 基础IO(IO操作)

目录 预备知识 复习C文件IO相关操作 printf相关函数 fprintf snprintf 读取文件 系统文件IO操作 open函数 umask()函数 open函数返回值 预备知识 1.你真的理解文件原理和操作了吗&#xff1f;不是语言问题&#xff0c;是系统问题2.是不是只有C/C有文件操作呢&#x…...

基于 Avue 的 CRUD 表格组件封装

在 components 文件夹中,创建一个新的 .vue 文件,例如:AvueCrudTable.vue。 透传父组件传递的属性和事件 : 1、利用v-bind=“ a t t r s " 支持所有 a v u e 的使用方法并在其基础上进行封装 2 、使用 v − o n = " attrs"支持所有 avue 的使用方法并在其基…...

树莓派学习笔记(十三)基于框架编写驱动代码

文章目录一、代码分析&#xff1a;二、源码一、代码分析&#xff1a; 在内核中由于代码文件多&#xff0c;避免函数名重复&#xff0c;使用static将函数的作用域限制在该文件内 内核的打印函数printk和printf类似 file_operations结构体使用符号“ . ”指定参数&#xff0c;省…...

vue事件修饰符之.prevent

.prevent 事件修饰符只是阻止默认事件&#xff0c;不会自动触发任何事件处理函数。因此&#xff0c;在使用 .prevent 事件修饰符时&#xff0c;需要自己编写相应的事件处理函数来处理事件。 例如&#xff0c;在上面的例子中&#xff0c;我们通过在表单上绑定 submit.prevent&q…...

【SpringCloud AlibabaSentinel实现熔断与限流】

本笔记内容为尚硅谷SpringCloud AlibabaSentinel部分 目录 一、Sentinel 1、官网 2、Sentinel是什么 3、下载 4、特性 5、使用 二、安装Sentinel控制台 1、sentinel组件由2部分构成 2、安装步骤 1.下载 2.运行命令 3.访问sentinel管理界面 三、初始化演示工程 …...

类与对象-封装

一、封装的意义封装是C面向对象三大特性之一语法&#xff1a; class name { 访问权限:属性行为 };注意&#xff1a;类中的属性和行为 统称为成员属性 又称 成员属性 / 成员变量行为 又称 成员函数 / 成员方法封装将属性和行为作为一个整体&#xff0c;表现生活中的事物例①&…...

【回忆杀】2012年拥有第一台电脑【致逝去的青春】

高中说起 在2012年的时候吧&#xff0c;高考过后&#xff0c;那个时候一门心思的想当一名体育老师【现在居然还有这个想法&#xff0c;哈哈】&#xff0c;最后没有考上自己希望的大学我记得好像是2012年7月的时候就去重庆投靠朋友&#xff0c;他教我做模具&#xff0c;2012年做…...

PointNeXt: Revisiting PointNet++ with Improved Training and Scaling Strategies

Abstract PointNet 是点云理解领域最有影响力的神经网络架构之一。虽然近期出现了 PointMLP 和 Point Transformer 等新型网络&#xff0c;它们的精度已经大大超过了 PointNet&#xff0c;但我们发现大部分性能提升是由于改进的训练策略&#xff0c;例如数据增强和优化技术以及…...

打印九九乘法表-课后程序(JavaScript前端开发案例教程-黑马程序员编著-第2章-课后作业)

【案例2-9】打印九九乘法表 一、案例描述 考核知识点 for双重循环 练习目标 掌握for循环应用。实现九九乘法表。 需求分析 九九乘法表相信大家一点也不陌生&#xff0c;之前见到的乘法表是印刷在课程本之上的。而在本案例中我们将用JavaScript代码来实现九九乘法表。 案例分…...

【Linux】基于阻塞队列的生产者消费者模型

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《学会Linux》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;为何要使用…...

【华为OD机试 2023最新 】 真正的密码(C++)

文章目录 题目描述输入描述输出描述用例题目解析C++题目描述 在一行中输入一个字符串数组,如果其中一个字符串的所有以索引0开头的子串在数组中都有,那么这个字符串就是潜在密码, 在所有潜在密码中最长的是真正的密码,如果有多个长度相同的真正的密码,那么取字典序最大的…...

差分算法(蓝桥杯复习+例题讲解+模板c++)

文章目录差分介绍差分应用区间加区间求和总结3729. 改变数组元素100. 增减序列文章首发于&#xff1a;My Blog 欢迎大佬们前来逛逛 差分介绍 差分是一种常见的算法&#xff0c;用于快速修改数组中某一段区间的值。 差分的思想就是预处理出数组的差分数组&#xff0c;然后修改…...

CSS+ JS 实现手电筒效果

前言概述 JavaScript 结合 CSS 打造的一款图片特效&#xff0c;当鼠标拖拽滑块时&#xff0c;让本该置灰的图片局部恢复本来的颜色。且该效果随着你的鼠标的按下时的移动而移动。 核心功能 图片置灰 拖拽功能 让滑块位置处的图片恢复本来的颜色 实现原理 这个的实现原理并不…...

2021地理设计组二等奖:基于InSAR和指数分析的地面沉降风

作品简介 一、作品背景 地面沉降是指地面高程的降低, 又称地面下沉或地沉, 是以缓慢、难以察觉的向下垂直运动为主, 是指在自然和人为因素作用下, 由于地壳表层土体压缩而导致区域性地面标高降低的一种环境现象。目前, 地面沉降己成为城市化进程中普遍存在的生态环境问题, 成为…...

计算机操作系统(第四版)第二章进程的描述与控制—课后习题答案

1.什么是前趋图&#xff1f;为什么要引入前趋图&#xff1f; 前趋图是一个有向无循环图&#xff0c;记为DAG&#xff0c;用于描述进程之间执行的先后关系。 2.试画出下面四条语句的前趋图&#xff1a; S1:axy; S2:bz1; S3:ca-b; S4:wc1; 3.为什么程序并发执行会产生间断性特征&…...

CAN通信----电路图

CAN通信----基本原理 一、CAN总线网络连接 1.闭环总线网络----ISO11898 闭环总线网络高速、短距离&#xff0c;它的总线最大长度为 40m&#xff0c;通信速度最高为 1Mbps&#xff0c;总线的两端各要求有一个120 欧的电阻。 2.开环总线网络----ISO11519 开环总线网络低速、…...

Windows系统安装ElasticSearch(一)

一 ES介绍Elasticsearch 是一个分布式可扩展的实时搜索和分析引擎,一个建立在全文搜索引擎 Apache Lucene(TM) 基础上的搜索引擎.当然 Elasticsearch 并不仅仅是 Lucene 那么简单&#xff0c;它不仅包括了全文搜索功能&#xff0c;还可以进行以下工作:分布式实时文件存储&#…...

linux 产生随机数 并遍历

1、产生随机数 varRANDOMvarRANDOM varRANDOMvar[ $var % 150 ] 2、产生不重复的随机数 $ entries($(shuf -i 0-149 -n 15)) $ echo “${entries[]}” 3、对随机数排序 $ entries($(shuf -i 0-149 -n 15 | sort -n)) $ echo “entries[]"12224549546678798393118119124140…...

【3.24】Mybatis常见面试题

Mybatis常见面试题 #{}和&#xffe5;{}的区别是什么&#xff1f; 【#】&#xff1a;底层执行SQL使用PreparedStatement对象&#xff0c;预编译SQL&#xff0c;相对安全。入参使用占位符的方式。 【$】&#xff1a;底层执行SQL使用Statement对象&#xff0c;入参使用SQL拼接的…...

IDEA 热部署,修改代码不用重启项目

热部署指在修改项目代码的时候不重启服务器让修改生效。安装JRebel and XRebelFile->Settings&#xff0c;然后Plugins-> Marketplace&#xff0c;输入JRebel&#xff0c;安装如下插件——JRebel and XRebel &#xff0c;重启idea激活JRebel and XRebel第一行输入网址&am…...

将 XLS 转换为 EXE:xlCompiler Crack

只需单击几下即可将Excel文件转换为应用程序 xl编译器无需编程即可将您的Excel电子表格转换为软件应用程序 将 XLS 转换为 EXE 将Excel文件转换为具有保护选项的应用程序。Excel 到 EXE 转换器为您提供了分发 Excel 模型的竞争优势和灵活性。将 Excel 的功能丰富的环境保存在应…...

【百面成神】spring基础12问,你能坚持到第几问

前 言 &#x1f349; 作者简介&#xff1a;半旧518&#xff0c;长跑型选手&#xff0c;立志坚持写10年博客&#xff0c;专注于java后端 ☕专栏简介&#xff1a;java面试宝典&#xff0c;特点&#xff1a;全、精、深、简&#xff0c;力求每个核心知识点1分钟回答好。 &#x1f3…...

javaSE类和对象(下)

目录君1.封装2.访问限定符3.包的定义及使用4.static成员变量5.static成员方法6.代码块及其分类实例代码块静态代码块静态代码块与实例代码块的执行顺序static成员变量(类变量)初始化1.封装 面向对象程序三大特性&#xff1a;封装、继承、多态。而类和对象阶段&#xff0c;主要…...

【数据结构】第四站:单链表力扣题(二)

目录 一、链表的回文结构 二、相交链表 三、环形链表 四、环形链表Ⅱ 五、复制带随机指针的链表 一、链表的回文结构 题目描述&#xff1a;链表的回文结构_牛客题霸_牛客网 对于这道题&#xff0c;如果没有前面的一些题的基础&#xff0c;是非常难做的&#xff0c;我们的思…...

KafKa知识汇总

前言 汇总相关知识 Kafka快速实战与基本原理详解...

【RV1126】调试GT911,1024x600 7寸 MIPI 电容触摸屏

文章目录一、驱动注册失败二、触摸屏可以触摸&#xff0c;但是x轴数据反了三、可以触摸了&#xff0c;但是Y轴数据跳变&#xff0c;几乎只有一半的屏幕是可以正常滑动的三、汇顶触摸屏配置文件解析四、使用新的配置文件4.1 新配置解决问题4.2 测试触摸的方法在kernel增加frame …...

C的强符号/弱符号

首先上代码和结果&#xff1a; 代码&#xff1a; #include <stdio.h> int k; int k; int main() {printf("addr of k %p\n", &k);printf("value of k %d\n", k);return 0; }结果&#xff1a; addr of k 00408074 value of k 0问题&…...

企业网站必须做可信认证吗/三亚百度推广地址

本文实例为大家分享了java封装前端查询条件的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下import hengyi.oa.mobile.exception.ServiceException;import java.io.UnsupportedEncodingException;import java.util.List;import java.util.Map;import java.util.Map.E…...

网站代码优化多少钱/天津网站推广

摘自&#xff1a;http://www.iplaysoft.com/robocode.html Robocode(用游戏来学习Java技术还是用Java来玩游戏&#xff1f;)用你的JAVA编程技术来玩游戏吧&#xff01;不会JAVA&#xff1f;那就用游戏来学习JAVA吧&#xff01;什么是Robocode? 其实我对机器人一直很感兴趣。我…...

wordpress animate css/厦门网络推广

前言 Zuul 是Netflix 提供的一个开源组件,致力于在云平台上提供动态路由&#xff0c;监控&#xff0c;弹性&#xff0c;安全等边缘服务的框架。也有很多公司使用它来作为网关的重要组成部分&#xff0c;碰巧今年公司的架构组决定自研一个网关产品&#xff0c;集动态路由&#…...

深圳网站建设公司设计/网站平台搭建

html页面在苹果手机内&#xff0c;safari浏览器&#xff0c;微信中滑动不流畅问题解决方案参考文章&#xff1a; &#xff08;1&#xff09;html页面在苹果手机内&#xff0c;safari浏览器&#xff0c;微信中滑动不流畅问题解决方案 &#xff08;2&#xff09;https://www.cn…...

更改wordpress后台登录地址/桂林seo顾问

一&#xff0c;暴露端口 根据官网教程&#xff0c;需要使用3000端口&#xff0c;但一般都是阿里云的安全组没有放行3000端口&#xff0c;致使安装好metabase后无法打开浏览页面。 通过阿里云控制台打开安全组规则&#xff0c;在入方向新增3000端口即可。 二&#xff0c;安装d…...

页面做的好看的网站/企业管理培训

问题背景&#xff1a; easyui 需要显示行号的时候&#xff0c;我们只需要设置 rownumbers: true, 但是 不管是在哪一页&#xff0c;行号都是从1开始&#xff0c;不能连续 我们在分页的 onSelectPage 函数里去执行 如下&#xff1a; onSelectPage: function (pageNo, pageSi…...