时间复杂度和空间复杂度是什么?

一、简介

【时间复杂度】是一个算法运行所需要的时间。【空间复杂度】是一个算法运行所需要的储存空间。

它们常常被人们用来检测一个算法的质量好坏。在实际操作中,这两个指标往往无法同时兼顾。这需要设计者综合各方面的实际情况做出取舍。算法原本是数学领域中涉及到的知识。后来,随着计算机的不断升级和发展,也开始在计算机领域中的大量使用。

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

时间频度

一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。并且一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度,记为 T(n)。因此,另一种更为通用的方法就出来了:「 大O符号表示法 」,即 T(n) = O(f(n))

最坏时间复杂度
算法的时间复杂度不仅与语句频度有关,还与问题规模及输入实例中各元素的取值有关。一般不特别说明,讨论的时间复杂度均是最坏情况下的时间复杂度。这就保证了算法的运行时间不会比任何更长。

 


二、时间复杂度量级

 1、常数时间

若对于一个算法,T(n)的上界与输入大小无关,则称其具有常数时间,记作 O(1) 时间。一个例子是访问数组中的单个元素,因为访问它只需要一条指令。但是,找到无序数组中的最小元素则不是,因为这需要遍历所有元素来找出最小值。这是一项线性时间的操作,或称 O(n) 时间。

2、对数时间

若算法的T(n) =O(logn),则称其具有对数时间。然而,由对数的换底公式,logan logb只有一个常数因子不同,这个因子在大O记法中被丢弃。因此记作O(logn),而不论对数的底是多少,是对数时间算法的标准记法。
常见的具有对数时间的算法有二叉树的相关操作和二分搜索。对数时间的算法是非常有效的,因为每增加一个输入,其所需要的额外计算时间会变小。

3、线性时间

如果一个算法的时间复杂度为O(n),则称这个算法具有线性时间,或O(n)时间。非正式地说,这意味着对于足够大的输入,运行时间增加的大小与输入成线性关系。例如,一个计算列表所有元素的和的程序,需要的时间与列表的长度成正比。这个描述是稍微不准确的,因为运行时间可能显著偏离一个精确的比例,尤其是对于较小的n。

4、线性对数时间

若一个算法时间复杂度T(n) = O(nlog n),则称这个算法具有线性对数时间。简单理解就是将时间复杂度为O(logn)的代码循环N遍的话,那么它的时间复杂度就是 O(n) * O(logN),也就是了O(nlogN)。从其表达式我们也可以看到,线性对数时间增长得比线性时间要快

...


三、复杂度与时间效率的关系 

c < log2n < n < n*log2n < n2 < n3 < 2n < 3n < n! 

其中c是一个常量,如果一个算法的复杂度为c 、 log2n 、n 、 n*log2n,那么这个算法时间效率比较高 ,如果是 2n,3n,n!,那么稍微大一些的n就会令这个算法不能动了,居于中间的几个则差强人意。

 


四、代码复杂度分析

1、常数阶O(1)

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

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

2、线性阶O(n)

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

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

3、对数阶O(logN)

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

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

4、线性对数阶O(nlogn)

int num1,num2;
    for(int i=0; i<n; i++){
        num1 += 1;
        for(int j=1; j<=n; j*=2){
            num2 += num1;
        }
    }

 

可以看出,决定算法复杂度的是执行次数最多的语句,这里是num2 += num1,一般也是最内循环的语句。分析步骤如下:

  1.  找到执行次数最多的语句
  2. 计算语句执行次数的数量级
  3.  用大O来表示结果

执行次数最多的语句为num2 += num1 >>> 语句频度可表示为 T(n) = n*log2n >>> 大O表示为:T(n) = O(n*log2n)

 

posted @ 2022-09-27 17:02  danielzzz  阅读(453)  评论(0编辑  收藏  举报