时间复杂度与空间复杂度

简介: 如何理解时间复杂度与空间复杂度

一 简介

算法本质上是一连串的计算步骤。对于同一个问题,我们可以使用不同的算法来获得相同的结果,可是在计算过程中,同一算法在不同的电脑里运行时,消耗的时间和资源却有很大的区别。那我们如何来比较不同算法之间的优劣性呢?时间复杂度与空间复杂度的作用,就是用来衡量一个算法的好坏的;

目前分析算法主要从「时间」和「空间」两个维度来进行分析。时间维度顾名思义就是算法需要消耗的时间,「时间复杂度」是常用的分析单位。空间维度代表算法需要占用的内存空间,我们通常用「空间复杂度」来分析。

所以,分析算法的效率主要从「时间复杂度」和「空间复杂度」来分析。很多时候我们两者不可兼得,有时候要用时间换空间,或者空间换时间。下面我们一起来分别了解「时间复杂度」和「空间复杂度」的计算方式。

二 时间复杂度BigO

想要从「时间维度」来了解一个算法,最简单的方法就是将算法运行一遍,然后计算花费的时间就可以了。

此方法可行,可是有很多弊端。只计算运行时间特别容易受到运行环境的影响,高性能和低性能的机器上出来的结果相差甚远。而且与测试时使用的数据规模也有很大的关系。

所以我们需要一种复杂度计算方式,不受计算机性能和程序数据的影响,「大O符号表示法」(BigO)就是这种计算方式,既 T(n) = O(f(n)),它表示一个算法的渐进时间复杂度。其中 f(n) 表示代码执行次数之和,O表示正比例关系。

BigO计算的是:当需要计算的数据的的数量级增加的时候,时间增长的趋势;

大O表示法:算法的渐进时间复杂度;
T(n)=O(f(n)):T(n)指的是时间复杂度,f(n)指的是代码执行的次数,O表示正比例关系;

示例1:

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

每个算法需要多少的运行时间呢?我们知道这个for loop有n个循环,假设其中 x++ 计算的消耗是一个单位,那么第一次循环是1单位,第二次循环是2单位,所以整个循环语句就要消耗n个单位。可以发现,消耗的单位时间随着循环的次数而变化,循环次数为1,时间为1单位;循环次数为10,时间为10单位;循环次数为n,时间为n单位。所以这个算法的「时间复杂度」可以表示为:T (n) = O(n)。

有人可能不同意了,因为严格计算下,int i = 1也要消耗1单位时间,i <= n和i++也都需要1单位时间,所以严格来说总时间是 T(n) = 1 + 3n。但是我们依然会简化为n,因为「大O表示法」用与表示计算的增长变化趋势,即表示的是n接近无限大的时候的。

1+3n的具体算法如下(不重要,此处可以忽略):
首先,i=1:执行一次;
后边的n层循环里:i<=n 、 i++ 、 x++,各自执行一次;
总共执行次数就是1+3N次,即用BjgO表示就是:O(1+3N),因为BigO表示的是N接近无限大的时候的值,此时,1与3的影响已经可以忽略了,所以可以直接写成O(1+3N)=O(N)次;

示例2:

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

在外层循环中,i 总共需要n层循环,在每一次内层循环中,j 也会循环n次。如果用「大O表示法」来计算,那么两个循环语句的复杂度就是O(n^2^);

我们把i <= n与i++看做一次,把j <= n; j++;x++看做一次,则时间复杂度就是O(n^2^),即随着数量n的增加,时间复杂度呈现指数级增长,这种算法非常可怕;

如果我们将这两个算法合并到一起:

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

整个算法复杂度就变为 O(n + n2),在n无限大的情况下,可以简化为 O(n2)。

常用的时间复杂度量级如下:
image.png

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

上面的时间复杂从上到下复杂度越来越大,也意味着执行效率越来越低。以下我们来讲解一些常用的量级:

  1. 常数阶O(1)
    只要没有循环或递归等复杂逻辑,无论代码执行多少行,代码复杂度都为O(1),如下:
int x = 0;
int y = 1;
int temp = x;
x = y;
y = temp;

上述代码在执行的时候,所消耗的时间不会随着特定变量的增长而增长,即使有几万行这样的代码,我们都可以用O(1)来表示它的时间复杂度。

  1. 线性阶O(n)
    我们在上述的例子中讲解过O(n)的算法:
for (int i = 1; i <= n; i++) {
   
   
    x++;
}

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

  1. 对数阶O(logN)
    来看以下的例子:
int i = 1;
while(i < n) {
   
   
    i = i * 2;
}

在上面的循环中,每次i都会被乘以2,也意味着每次 i 都离 n 更进一步。那需要多少次循环 i 才能等于或大于 n 呢,也就是求解2的x次方等于n,答案x=log2^n^。 也就是说循环 log2^n次之后,i会大于等于n,这段代码就结束了。所以此代码的复杂度为:O(logN)。

  1. 线性对数阶O(nlogN)
    线性对数阶O(nlogN)很好理解,也就是将复杂度为O(logN)的代码循环n遍:
for(int i = 0; i <= n: i++) {
   
   
    int x = 1;
    while(x < n) {
   
   
        x = x * 2;
    }
}

因为每次循环的复杂度为O(logN),所以n * logN = O(nlogN)

  1. 平方阶O(n²)
    在之前的例子我们也讲过,O(n²)就是将循环次数为n的代码再循环n遍:
for (int i = 1; i <= n; i++) {
   
   
    for (int j = 1; j <= n; j++) {
   
   
        x++;
    }
}

O(n²)的本质就是n * n,如果我们将内层的循环次数改为m:

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

复杂度就变为 n m = O(n m)。

关于一些更高的阶级比如O(n³)或者O(n^k),我们可以参考O(n²)来理解即可,O(n³)相当于三层循环,以此类推。

除了「大O表示法」还有其他「平均时间复杂度」、「均摊时间复杂度」、「最坏时间复杂度」、「最好时间复杂度」等等分析指数,但是最常用的依然是「大O表示法」。

三 空间复杂度

既然「时间复杂度」不是计算程序具体消耗的时间,「空间复杂度」也不是用来计算程序具体占用的空间。随着问题量级的变大,程序需要分配的内存空间也可能会变得更多,而「空间复杂度」反映的则是内存空间增长的趋势。

常用的空间复杂度

比较常用的空间复杂度有:O(1)、O(n)、O(n²)。在下面的例子中,我们用 S(n) 来定义「空间复杂度」。

3.1 O(1)空间复杂度

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

int x = 0;
int y = 0;
x++;
y++;

其中x, y所分配的空间不随着处理数据量变化,因此「空间复杂度」为 O(1)

3.2 O(n)空间复杂度

以下的代码给长度为n的数组赋值:

int[] newArray = new int[n];
for (int i = 0; i < n; i++) {
   
   
    newArray[i] = i;
}

在这段代码中,我们创建了一个长度为 n 的数组,然后在循环中为其中的元素赋值。因此,这段代码的「空间复杂度」取决于 newArray 的长度,也就是 n,所以 S(n) = O(n)。

以上便是「时间复杂度」和「空间复杂度」的简单介绍啦,简单来说,这两个复杂度反映的是,随着问题量级的增大,时间和空间增长的趋势。学会了复杂度的分析,我们就可以对比算法之间的优劣势啦

相关文章
|
存储 人工智能 缓存
空间复杂度介绍
空间复杂度介绍
137 0
|
1月前
|
机器学习/深度学习 存储 算法
一篇文章理解时间复杂度和空间复杂度
一篇文章理解时间复杂度和空间复杂度
36 0
|
5月前
|
算法 程序员 存储
时间复杂度与空间复杂度详解
时间复杂度与空间复杂度详解
|
6月前
|
算法
了解时间复杂度和空间复杂度
在学习数据结构前,我们需要了解时间复杂度和空间复杂度的概念,这能够帮助我们了解数据结构。 算法效率分为时间效率和空间效率
40 1
|
6月前
|
机器学习/深度学习 存储 算法
时间复杂度和空间复杂度
时间复杂度和空间复杂度
|
机器学习/深度学习 算法
时间复杂度和空间复杂度详解
时间复杂度和空间复杂度详解
270 0
|
算法
时间复杂度与空间复杂度
时间复杂度与空间复杂度
|
6月前
|
机器学习/深度学习 算法 搜索推荐
2.时间复杂度与空间复杂度
2.时间复杂度与空间复杂度
48 0
|
算法
【时间复杂度和空间复杂度】
【时间复杂度和空间复杂度】
59 0
|
存储 机器学习/深度学习 并行计算
空间复杂度
空间复杂度(Space Complexity)是用于描述算法在执行过程中所需占用空间大小的量度。空间复杂度通常与算法的输入规模成正比,表示算法在处理不同规模数据时所需的空间资源。空间复杂度可以帮助我们评估算法的效率,以及在实际应用中可能产生的内存消耗。
92 0