一层循环时间复杂度_算法的时间与空间复杂度(一看就懂)

b735c5682d5c60c026961e10a46a77b1.png

算法(Algorithm)是指用来操作数据、解决程序问题的一组方法。对于同一个问题,使用不同的算法,也许最终得到的结果是一样的,但在过程中消耗的资源和时间却会有很大的区别。

那么我们应该如何去衡量不同算法之间的优劣呢?

主要还是从算法所占用的「时间」和「空间」两个维度去考量。

  • 时间维度:是指执行当前算法所消耗的时间,我们通常用「时间复杂度」来描述。
  • 空间维度:是指执行当前算法需要占用多少内存空间,我们通常用「空间复杂度」来描述。

因此,评价一个算法的效率主要是看它的时间复杂度和空间复杂度情况。然而,有的时候时间和空间却又是「鱼和熊掌」,不可兼得的,那么我们就需要从中去取一个平衡点。

下面我来分别介绍一下「时间复杂度」和「空间复杂度」的计算方式。

一、时间复杂度

我们想要知道一个算法的「时间复杂度」,很多人首先想到的的方法就是把这个算法程序运行一遍,那么它所消耗的时间就自然而然知道了。

这种方式可以吗?当然可以,不过它也有很多弊端。
这种方式非常容易受运行环境的影响,在性能高的机器上跑出来的结果与在性能低的机器上跑的结果相差会很大。而且对测试时使用的数据规模也有很大关系。再者,并我们在写算法的时候,还没有办法完整的去运行呢。

因此,另一种更为通用的方法就出来了:「 大O符号表示法 」,即 T(n) = O(f(n))

我们先来看个例子:

for(i=1; i<=n; ++i)
{j = i;j++;
}

通过「 大O符号表示法 」,这段代码的时间复杂度为:O(n) ,为什么呢?

在 大O符号表示法中,时间复杂度的公式是: T(n) = O( f(n) ),其中f(n) 表示每行代码执行次数之和,而 O 表示正比例关系,这个公式的全称是:算法的渐进时间复杂度

我们继续看上面的例子,假设每行代码的执行时间都是一样的,我们用 1颗粒时间 来表示,那么这个例子的第一行耗时是1个颗粒时间,第三行的执行时间是 n个颗粒时间,第四行的执行时间也是 n个颗粒时间(第二行和第五行是符号,暂时忽略),那么总时间就是 1颗粒时间 + n颗粒时间 + n颗粒时间 ,即 (1+2n)个颗粒时间,即: T(n) = (1+2n)*颗粒时间,从这个结果可以看出,这个算法的耗时是随着n的变化而变化,因此,我们可以简化的将这个算法的时间复杂度表示为:T(n) = O(n)

为什么可以这么去简化呢,因为大O符号表示法并不是用于来真实代表算法的执行时间的,它是用来表示代码执行时间的增长变化趋势的。

所以上面的例子中,如果n无限大的时候,T(n) = time(1+2n)中的常量1就没有意义了,倍数2也意义不大。因此直接简化为T(n) = O(n) 就可以了。

常见的时间复杂度量级有:

  • 常数阶O(1)
  • 对数阶O(logN)
  • 线性阶O(n)
  • 线性对数阶O(nlogN)
  • 平方阶O(n²)
  • 立方阶O(n³)
  • K次方阶O(n^k)
  • 指数阶(2^n)

上面从上至下依次的时间复杂度越来越大,执行的效率越来越低。

下面选取一些较为常用的来讲解一下(没有严格按照顺序):

  1. 常数阶O(1)

无论代码执行了多少行,只要是没有循环等复杂结构,那这个代码的时间复杂度就都是O(1),如:

int i = 1;
int j = 2;
++i;
j++;
int m = i + j;

上述代码在执行的时候,它消耗的时候并不随着某个变量的增长而增长,那么无论这类代码有多长,即使有几万几十万行,都可以用O(1)来表示它的时间复杂度。

  1. 线性阶O(n)

这个在最开始的代码示例中就讲解过了,如:

for(i=1; i<=n; ++i)
{j = i;j++;
}

这段代码,for循环里面的代码会执行n遍,因此它消耗的时间是随着n的变化而变化的,因此这类代码都可以用O(n)来表示它的时间复杂度。

  1. 对数阶O(logN)

还是先来看代码:

int i = 1;
while(i<n)
{i = i * 2;
}

从上面代码可以看到,在while循环里面,每次都将 i 乘以 2,乘完之后,i 距离 n 就越来越近了。我们试着求解一下,假设循环x次之后,i 就大于 2 了,此时这个循环就退出了,也就是说 2 的 x 次方等于 n,那么 x = log2^n
也就是说当循环 log2^n 次以后,这个代码就结束了。因此这个代码的时间复杂度为:O(logn)

  1. 线性对数阶O(nlogN)

线性对数阶O(nlogN) 其实非常容易理解,将时间复杂度为O(logn)的代码循环N遍的话,那么它的时间复杂度就是 n * O(logN),也就是了O(nlogN)。

就拿上面的代码加一点修改来举例:

for(m=1; m<n; m++)
{i = 1;while(i<n){i = i * 2;}
}
  1. 平方阶O(n²)

平方阶O(n²) 就更容易理解了,如果把 O(n) 的代码再嵌套循环一遍,它的时间复杂度就是 O(n²) 了。
举例:

for(x=1; i<=n; x++)
{for(i=1; i<=n; i++){j = i;j++;}
}

这段代码其实就是嵌套了2层n循环,它的时间复杂度就是 O(n*n),即 O(n²)
如果将其中一层循环的n改成m,即:

for(x=1; i<=m; x++)
{for(i=1; i<=n; i++){j = i;j++;}
}

那它的时间复杂度就变成了 O(m*n)

  1. 立方阶O(n³)K次方阶O(n^k)

参考上面的O(n²) 去理解就好了,O(n³)相当于三层n循环,其它的类似。

除此之外,其实还有 平均时间复杂度、均摊时间复杂度、最坏时间复杂度、最好时间复杂度 的分析方法,有点复杂,这里就不展开了。

二、空间复杂度

既然时间复杂度不是用来计算程序具体耗时的,那么我也应该明白,空间复杂度也不是用来计算程序实际占用的空间的。

空间复杂度是对一个算法在运行过程中临时占用存储空间大小的一个量度,同样反映的是一个趋势,我们用 S(n) 来定义。

空间复杂度比较常用的有:O(1)、O(n)、O(n²),我们下面来看看:

  1. 空间复杂度 O(1)

如果算法执行所需要的临时空间不随着某个变量n的大小而变化,即此算法空间复杂度为一个常量,可表示为 O(1)
举例:

int i = 1;
int j = 2;
++i;
j++;
int m = i + j;

代码中的 i、j、m 所分配的空间都不随着处理数据量变化,因此它的空间复杂度 S(n) = O(1)

  1. 空间复杂度 O(n)

我们先看一个代码:

int[] m = new int[n]
for(i=1; i<=n; ++i)
{j = i;j++;
}

这段代码中,第一行new了一个数组出来,这个数据占用的大小为n,这段代码的2-6行,虽然有循环,但没有再分配新的空间,因此,这段代码的空间复杂度主要看第一行即可,即 S(n) = O(n)

以上,就是对算法的时间复杂度与空间复杂度基础的分析,欢迎大家一起交流。

欢迎继续看 算法之

不止思考(奎哥):算法一看就懂之「 数组与链表 」​zhuanlan.zhihu.com
686eb0cdb6eef0512c26495d5b118563.png

不止思考(奎哥):算法一看就懂之「 堆栈 」​zhuanlan.zhihu.com
edd818b5618de7019236b8b42bb4e907.png

不止思考(奎哥):算法一看就懂之「 队列 」​zhuanlan.zhihu.com
716bcdeb1352d415c7fe342609a805a4.png

,以及

不止思考(奎哥):算法一看就懂之「 递归 」​zhuanlan.zhihu.com
b8bf91debcf5f1aba44d3c1198c55d79.png

算法与数据结构相关文章会持续更新,欢迎关注。

本文原创发布于微信公众号「 不止思考 」,欢迎关注,交流更多的 互联网认知、工作管理、大数据、Web、区块链技术。

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

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

相关文章

用ajax替换html代码,替换Ajax响应一个div的内部HTML(Replace inner HTML of a div w

我试图一些时间间隔后改变一个div的内部HTML。 我得到我想要使用Ajax正确的反应。 但无法取代内HTML的后&#xff0c;并用Ajax响应地选择。 什么是错我的代码..HTML51 seconds ago58 seconds ago.....10 minute agoĴ查询setInterval(function() {$( ".time" ).each(…

java 审批流_一文读懂工作流

网上关于工作流引擎有比较多的简介&#xff0c;也有很多工作流的实际应用场景。本文结合笔者多年对工作流的经验来阐述一下对工作流的理解。一、什么是工作流&#xff1f;先贴上wiki百科对于工作流的定义工作流&#xff08;Workflow&#xff09;&#xff0c;是对工作流程及其各…

postgresql 查询序列_时间序列数据库(TSDB)初识与选择

作者&#xff1a;码哥字节 如需转载联系我的公众号背景 这两年互联网行业掀着一股新风&#xff0c;总是听着各种高大上的新名词。大数据、人工智能、物联网、机器学习、商业智能、智能预警啊等等。以前的系统&#xff0c;做数据可视化&#xff0c;信息管理&#xff0c;流程控制…

concurrenthashmap实现原理_Mybatis:PageHelper分页插件源码及原理剖析

PageHelper是一款好用的开源免费的Mybatis第三方物理分页插件&#xff0c;其实我并不想加上好用两个字&#xff0c;但是为了表扬插件作者开源免费的崇高精神&#xff0c;我毫不犹豫的加上了好用一词作为赞美。原本以为分页插件&#xff0c;应该是很简单的&#xff0c;然而PageH…

计算机网络dst,计算机网络基础课程—Socket接口

什么是TCP/IP------本课程的主要部分TCP/IP如何工作-----TCP/IP软件结构与实现如何用TCP/IP-------TCP/IP应用程序编程接口前面说过&#xff0c;TCP/IP标准并不指定应用程序与TCP/IP协议软件的接口&#xff0c;但并不是说没有提供任何指导&#xff0c;首先&#xff0c;它指定了…

python输入圆的半径公式_[图文]铁路曲线正矢的计算公式

一、圆曲线正矢的计算1.1 圆曲线正矢的计算公式取圆曲线上两点拉一直线,叫做弦。弦上任意点至曲线上的垂直距离叫矢或叫矢距。在弦中央点的矢距叫正矢(下图)。AB一弦;AC、CB一半弦;CD一正矢;EF一矢距正矢计算公式为其中: f-正矢 C-弦长 R-半径 式中单位均为m。公式用文字表示即…

docker 安装nacos_康过来!Nacos配置和管理微服务的使用

Nacos 具有如下特性:服务发现和服务健康监测&#xff1a;支持基于DNS和基于RPC的服务发现&#xff0c;支持对服务的实时的健康检查&#xff0c;阻止向不健康的主机或服务实例发送请求&#xff1b;动态配置服务&#xff1a;动态配置服务可以让您以中心化、外部化和动态化的方式管…

matlab中如何调用gpu进行并行计算_极致安卓-Termux/Aid learning开启WebGL手机GPU并行计算...

在我的之前的测评中&#xff0c;我利用Termux和Aid Learning测试过基于C/C的openmp并行程序&#xff0c;基于Java的并行程序&#xff0c;还有基于MPI以及基于Java的分布式集群并行。但是很遗憾&#xff0c;一直无法成功开发基于OpenCL的GPU并行编程。这是主要是因为Android并没…

python默认编码方式_关于设置python默认编码方式的问题

2019-8-27 07:45:36 本帖最后由 傻纸 于 2019-8-27 10:02 编辑 查了一会资料得出的结论是如果你用的是python3.x&#xff0c;那么就最好别去设置sys.defaultencoding或者sys.stdout.encoding 记住在需要编码的时候用encode&#xff0c;解码的时候decode就可以了。。。 这个问题…

计算机科学与技术是属于什么学科,计算机科学与技术专业属于什么大类 属于哪个学科...

近日&#xff0c;有很多人咨询小编计算机科学与技术专业属于什么大类 属于哪个学科&#xff1f;现在小编统一回复一下大家计算机科学与技术专业属于工学类&#xff0c;下面是关于计算机科学与技术专业详细的介绍。1计算机科学与技术专业门类及学科介绍专业名称专业代码门类学科…

matlab imread_MATLAB图像处理:29:在几何变换输出中指定填充值

本示例说明如何指定imwarp执行几何变换时使用的填充值。执行转换时&#xff0c;输出图像中通常会有一些像素不属于原始输入图像。必须为这些像素分配一些值&#xff0c;称为填充值。默认情况下&#xff0c;imwarp将这些像素设置为零&#xff0c;并显示为黑色。使用FillValues参…

micopython 18b20_MicroPython控制8*8LED点阵显示温度

MicroPython顾名思义就是可以在单片机上跑的Python&#xff0c;借助Micro Python&#xff0c;用户完全可以通过Python脚本语言实现硬件底层的访问和控制&#xff0c;比如说控制LED灯泡、LCD显示器、读取电压、控制电机、访问SD卡等。目前支持MicroPython的开发板有好几种&#…

ip变更会影响账号登陆吗_【教程】PUBG账号被盗导致封禁申诉解封教程

很多朋友询问PUBG在被盗号后被盗号者开挂导致永封该如何申诉解封&#xff0c;现在结合一些玩家被盗号及成功申诉的经历&#xff0c;详列一下步骤。本方法只适用于被盗后开挂导致封禁的账号&#xff0c;那些自己开挂被封的孤儿不用往下看了。一.先向steam客服申诉 找回自己的ste…

滤镜怎么调_手机、电脑怎么剪辑视频?真心求推荐实用工具

自从加入了短视频自媒体运营这个行业以后&#xff0c;我就开始接触到各种各样的手机、电脑视频剪辑、制作软件&#xff0c;用它们来处理、完成被安排到的工作任务。很多时候&#xff0c;我也用它们来剪视频&#xff0c;借此来练练手、积累下素材。记得刚进入这个行业的时候&…

2021计算机基础知识题库,2021~2021计算机基础知识练习题

2021~2021计算机基础知识练习题 2021~2021计算机基础知识练习题 北京联合大学 2021~2021计算机基础知识练习题 一、选择题 1.记录在存储介质上的一组相关信息的集合称为______。 A)程序 B)磁盘 C)软件 D)文件 2.当一个文件更名后&#xff0c;文件的内容会______。 A)完全消失 B…

计算机背板知识,你知道背板的选购技巧吗?

原标题&#xff1a;你知道背板的选购技巧吗&#xff1f;背板就是母板&#xff0c;子板插在上面构成系统&#xff0c;计算机背板说成背板也成立&#xff0c;只不过背板更多的知识线路板而已&#xff0c;没有实际的器件&#xff0c;只起信号通路作用。背板在设备机箱的后面。一般…

git 切换分支_git 入门教程之分支总览

分支就是一条独立的时间线,既有分支,必有主干,正如一棵树谈到树枝,必有树干一样的道理.我们先前对git 的全部操作默认都是在主干上进行的,这个主干也是一种特殊的分支,名为 master 分支.无论是穿越历史还是撤销更改,我们都或多或少接触过时间线,git 管理的版本串在一起就组成了…

正在锁定计算机 win7转圈圈打不开,Win7网络连接图标一直转圈的原因和解决方法...

Win7网络连接图标一直转圈是什么情况&#xff1f;如果用户发现Win7系统中的网络图标一直处在转圈状态&#xff0c;则表示该网络不能正常加载&#xff0c;且无法识别&#xff0c;笔者通过检查发现网络依赖的服务Network List Service没有自动启动&#xff0c;启动之后可解决该问…

jvm内存模型和java内存模型_JVM运行时内存模型综述

JVM内存模型JVM分为五个区域&#xff1a;虚拟机栈、本地方法栈、方法区、堆、程序计数器。JVM不同区域的占用内存大小不同&#xff0c;一般情况下堆最大&#xff0c;程序计数器较小。JVM五个区中虚拟机栈、本地方法栈、程序计数器为线程私有&#xff0c;方法区和堆为线程共享区…

getline没有与参数列表匹配的重载函数_C++新增基础功能解析—函数重载功能的使用...

喜欢的可以收藏转发加关注“函数重载”指的是可以有多个同名的函数&#xff0c;因此 名称进行了重载。这两个术语指的是同一回事&#xff0c;但我们通常使用函数重载。可以通过函数重载来设计• 系列函数——它们完成相同的工作&#xff0c;但使用不同的参数列表。重载函数就像…