杂谈-时间复杂度和空间复杂度

时间复杂度我们需要了解:什么是时间复杂度,怎么去算时间复杂度

为什么提到了时间复杂度的概念?

之后我们会学习到许多的算法,用于解决实际问题,如果说数据结构是一种用于抽象化实际物体,将其用一系列数据构造出来,并且由物体所处事件所展示出的特征,以不同的逻辑结构组合同一类型的一系列数据的代码,那么算法就是,针对这些特殊的数据结构,以及需要处理事件的特征,通过巧妙的构思,基于计算机语言和计算机处理数据的强大算力,帮助我们计算出问题的答案

这个特征就十分鲜明了,我们通过对物体和物体所在的时间进行整体分析,设置专属于该物体的存储结构和更适合处理该事件的逻辑结构,以这种整体结构为框架的前提下,进行相对应算法的设计以解决实际问题,这应该就是“数据结构与算法基础”系列开设的初衷

而上述内容算是一个开场白,为介绍事件复杂度做了铺垫,那么我们下面以一个例子作为介绍时间复杂度的引子

引子

关于最短路径问题:

在一个图结构中(图的相关知识可进行离散数学或其他数据结构相关知识的了解),由于路径长短或者权重的问题,会造成一个节点到另一个节点有多条路径但是其可到达的最短路径只有一条(当然不排除有多条),所以我们需要设计一个算法来找出两节点间的最短路径,基于我们所设计好的对应现实实际问题的图结构

这里我们的前人都进行过思考并且留下了众多久经考验的好思想好算法,如

迪杰斯特拉算法、弗洛伊德算法、福特算法、SPFA、A*...

那么现在我们已经手握法宝,知道了问题如何解决了,但是时间就是金钱,对症下药往往能使问题更快速的解决,而且有的问题如果特征过于明显,就更需要相对应的算法进行处理,而我们进行评判的标准,就是时间复杂度和空间复杂度

那么从时间复杂度和空间复杂度的角度来看,哪一个又更重要一些?我只能说以前在计算机存储空间有限的情况下更注重空间利用,而现在我们更考虑时间效率

评判时间长短的标准

那自然,我们需要设置标准来评判某个算法或者某个程序运行的时间和利用的空间

所以我们进行过程分析,来看一看评判流程是怎么产生的

我们在编写代码的过程中会有以下流程

读题想思路 写代码 提交运行 看反馈(根据反馈能知道正确性,时间 空间)

事后统计法

这是一个常规流程,平时我们进行一些练习都是这么干的,有一个专业性强一些的名词解释其为:事后统计法

但是有一个问题,就是我们只能在出结果的那一刻才能知道自己的代码是否存在问题,这样在一整个流程中,如果出现问题,只能在前面所有的流程走完以后才可以得到结果,如果将上述所有流程作为时间复杂度的评价的话未免有些头重脚轻了,所以该方法不可取为标准(马后炮)

另外一个问题就是受环境影响大,在一台性能优秀的计算机上,其可以做到很快运行结束,但是将其放在另一个性能很差的计算机上,运行时间就会拉慢

还是有优点的,就是时间统计精确

但是我们不将其作为我们估计时间复杂度的判断条件,因为没有统一性

分析时间复杂度的思路

所以时间复杂度,我们依靠估算代码的运行时间来比较,不精确估测,数量级准确即可

小引

承接上面代码流程的操作问题,我们思考,如何进行代码编写?我们需要对算法进行时间复杂度的估计,在基本符合要求后进行代码编写(主要是对方法进行选择,不造成凭感觉来导致的代码出错)

估测也要有估测的具体方法,而时间复杂度,就是以写好的代码为评测标准,累计该程序代码中的语句执行次数,并求其数量级即可

而语句执行的频度,即语句的执行次数,一定会受到处理数据的规模的影响,因为我们的算法一定是对数据的处理,必要带入数据,那自然会带入与其相同的数据,即问题数量总和

一般在代码中,我们先找循环,循环会带入代码的重复执行,除了循环,我们还需要注意递归操作

常见的算法时间复杂度由小到大依次为: O(1)<O(log2n)<O(n)<O(nlog2n)<O(n^2)<O(n^3)<...<O(2^n)<O(n!)

那么由此我们其实已经知道了一件事,时间复杂度的计算,就是一种数学计算,凭借经验进行时间复杂度的判断是目前所需要培养的一种能力,经验也是可以总结的嘛,所以下面有针对语句的分析,我们可以来看一下

分析法则

1、对于一些简单的输入输出语句或赋值语句,近似认为需要O(1)时间

2、对于顺序结构,需要依次执行一系列语句所用的时间可采用大O下“求和法则”。求和法则:是指若算法的2个部分时间复杂度分别为 T1(n)=O(f(n))和 T2(n)=O(g(n),则T(n)+T2n)=O(max(f(n), g(n)))。 特别地若T1(m)=O(f(m)),T2(n)=O(g(n)),则 T1(m)+T2(n)=O(f(m) + g(n))

3、对于选择结构,如if语句,它的主要时间耗费是在执行then字句或else字句所用的时间,需注意的是检验条件也需要O(1)时间

4、对于循环结构,循环语句的运行时间主要体现在多次迭代中执行循环体以及检验循环条件的时间耗费,一般可用大O下”乘法法则”。乘法法则: 是指若算法的2个部分时间复杂度分别为 T1(n)=O(f(n))和T2(n)=O(g(n)),则 T1 * T2=O(f(n) * g(n))

5、对于复杂的算法可以将它分成几个容易估算的部分,然后利用求和法则和乘法法则技术整个算法的时间复杂度。另外还有以下2个运算法则:(1) 若g(n)=O(f(n)),则O(f(n))+ O(g(n))= O(f(n));(2) O(Cf(n))=O(f(n))其中C是一个正常数

时间复杂度还可以进一步分为:最好、最坏、平均和摊均

按照处理数据的事件具体分析,比如事件在什么条件下最难进行,那么我们就将最难的一组数据带入进行算法时间复杂度的测算

最好最坏的意思同上

而均摊时间复杂度,听起来跟平均时间复杂度有点儿像。对于初学者来说,这两个概念确实非常容易弄混。我前面说了,大部分情况下,我们并不需要区分最好、最坏、平均三种复杂度。平均复杂度只在某些特殊情况下才会用到,而均摊时间复杂度应用的场景比它更加特殊、更加有限。

什么时候会用到时间复杂度的测算?

1.为了算而算,比如考研,找工作的笔试

int sum = 0;
for(int i=1;i<n;i++)
    for(int j=0;j<i;j++)
        sum++;

A.O(logn);

B.O(n);

C.O(nlogn);

D.O(n^2)

这道题选B。j随着i的递增记录为2的i次,但是i本身的数量为log2n次,那么2^log2n为n

以for语句的循环次数为基准,对应好其嵌套语句中的次数

总得来说还是应试教育的那一套,不掉以轻心就好

2.在竞赛中,程序的运行时间基本要求不超过1s,而1s大概是10^8个代码量,如果所写代码的最差情况远远超过这个数目,那么就需要重新选择

空间复杂度二三事

类似于时间复杂度的讨论,一个算法的空间复杂度(Space Complexity)S(n)定义为该算法所耗费的存储空间,它也是问题规模n的函数。渐近空间复杂度也常常简称为空间复杂度。

空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大小的量度。一个算法在计算机存储器上所占用的存储空间,包括存储算法本身所占用的存储空间,算法的输入输出数据所占用的存储空间和算法在运行过程中临时占用的存储空间这三个方面。算法的输入输出数据所占用的存储空间是由要解决的问题决定的,是通过参数表由调用函数传递而来的,它不随本算法的不同而改变。存储算法本身所占用的存储空间与算法书写的长短成正比,要压缩这方面的存储空间,就必须编写出较短的算法。算法在运行过程中临时占用的存储空间随算法的不同而异,有的算法只需要占用少量的临时工作单元,而且不随问题规模的大小而改变,我们称这种算法是“就地”进行的,是节省存储的算法;有的算法需要占用的临时工作单元数与解决问题的规模n有关,它随着n的增大而增大,当n较大时,将占用较多的存储单元,例如快速排序和归并排序算法就属于这种情况。

但竞赛中的算法重点不会关注该问题,但设置的空间不要超过10^7

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值