算法基础--时间/空间复杂度


前言

算法是一组用于操作数据和解决问题的方法。尽管不同算法在解决同一问题时可能得到相同结果,但它们在资源消耗和执行时间上可能存在显著差异。
评估不同算法的优劣应主要考虑时间空间两个维度。

时间维度指算法执行所需的时间,通常用时间复杂度描述。
空间维度指算法执行所需的内存空间,通常用空间复杂度描述。

评估算法效率的关键在于其时间复杂度和空间复杂度。然而,有时时间和空间是一种取舍的关系,需要在二者之间取得平衡。

一、时间复杂度

评估算法的时间复杂度时,许多人可能首先考虑运行算法程序并测量其消耗的时间。尽管这种方法可行,但存在一些缺点。
这种方法容易受到运行环境的影响,在性能较高的计算机上运行的结果可能与在性能较低的计算机上运行的结果有很大差异。此外,测试数据规模对结果也有重要影响。另外,在编写算法时,可能无法完全运行算法。
因此,另一种更通用的方法是使用「大O符号表示法」,即 T(n) = O(f(n)),来描述算法的时间复杂度。

1.1 时间复杂度公式

时间复杂度的公式是: T(n) = O( f(n) )
有关此公式的解释如下:

  • 其中f(n) 表示每行代码执行次数之和,而 O 表示正比例关系,这个公式的全称是:算法的渐进时间复杂度。
  • 去简化:大O符号表示法并不是用于来真实代表算法的执行时间的,它是用来表示代码执行时间的增长变化趋势的。

去简化示例:

for(i=1; i<=n; ++i)   //第1行
{                     //第2行    
   j = i;			  //第3行    
   j++;               //第4行    
}                     //第5行    

假设每行代码的执行时间都是一样的,用 1s来表示,那么

这个例子的第一行耗时是1s时间,
第三行的执行时间是 ns时间,
第四行的执行时间也是 ns时间(第二行和第五行是符号,暂时忽略),
那么总时间就是 1s时间 + ns时间 + ns时间 ,即 (1+2n)s个时间,即: T(n) = (1+2n)s 时间,
可以看出这个算法的耗时是随着n的变化而变化,因此如果n无限大的时候,T(n) = time(1+2n)中的常量1就没有意义了,倍数2也意义不大。因此直接简化为T(n) = O(n) 就可以了。

1.2 常见的时间复杂度量级

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

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

1.3 时间复杂度量级示例

1.3.1 常数阶O(1)

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

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

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

1.3.2 对数阶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.3.3 线性阶O(n)

如:

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

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

1.3.4 线性对数阶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.3.5 平方阶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.3.6 立方阶O(n³)、K次方阶O(n^k)

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


二、空间复杂度

空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大小的量度,记做S(n)=O(f(n))。
空间复杂度比较常用的有:O(1)、O(n)、O(n²)

2.1 O(1)

空间复杂度为O(1)的示例:

public void printNumber(int number) {
    System.out.println(number);
}

在这个示例中,无论输入的数字是多少,该函数只需要固定的空间来存储一个数字的内存空间,因此空间复杂度为O(1)。

2.2 O(n)

空间复杂度为O(n)的示例:

public void printNumbers(int[] numbers) {
    for (int i = 0; i < numbers.length; i++) {
        System.out.println(numbers[i]);
    }
}

在这个示例中,函数接收一个整型数组作为参数,然后遍历整个数组并打印每个元素。随着输入数组大小的增加,需要存储的元素数量也相应增加,因此空间复杂度为O(n)。

2.3 O(n²)

空间复杂度为O(n²)的示例:

public void printMatrix(int[][] matrix) {
    for (int i = 0; i < matrix.length; i++) {
        for (int j = 0; j < matrix[i].length; j++) {
            System.out.print(matrix[i][j] + " ");
        }
        System.out.println();
    }
}

在这个示例中,函数接收一个二维整型数组作为参数,然后遍历整个二维数组并打印每个元素。由于有两层嵌套循环,随着输入二维数组的大小增加,需要存储的元素数量将呈二次方增长,因此空间复杂度为O(n²)

三、常用算法的时间复杂度

3.1 O(1)相关算法

O(1)就是最低的时空复杂度了,也就是耗时/耗空间与输入数据大小无关,无论输入数据增大多少倍,耗时/耗空间都不变。 哈希算法就是典型的O(1)时间复杂度,无论数据规模多大,都可以在一次计算后找到目标(不考虑冲突的话)

3.2 O(logn)相关算法

比如O(logn),当数据增大n倍时,耗时增大logn倍(这里的log是以2为底的,比如,当数据增大256倍时,耗时只增大8倍,是比线性还要低的时间复杂度)。二分查找就是O(logn)的算法,每找一次排除一半的可能,256个数据中查找只要找8次就可以找到目标。

3.3 O(n)相关算法

时间复杂度为O(n),就代表数据量增大几倍,耗时也增大几倍。比如常见的遍历算法。

3.4 O(nlogn)相关算法

O(nlogn)同理,就是n乘以logn,当数据增大256倍时,耗时增大256*8=2048倍。这个复杂度高于线性低于平方。归并排序就是O(nlogn)的时间复杂度。

3.5 O(n^ 2)相关算法

再比如时间复杂度O(n^ 2),就代表数据量增大n倍时,耗时增大n的平方倍,这是比线性更高的时间复杂度。比如冒泡排序,就是典型的O(n^2)的算法,对n个数排序,需要扫描n×n次。

参考链接:
算法的时间与空间复杂度(一看就懂)

相关推荐

  1. 算法基础--时间/空间复杂

    2024-04-12 13:14:02       35 阅读
  2. 算法时间复杂空间复杂

    2024-04-12 13:14:02       32 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-12 13:14:02       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-12 13:14:02       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-12 13:14:02       87 阅读
  4. Python语言-面向对象

    2024-04-12 13:14:02       96 阅读

热门阅读

  1. 意得辑意得辑

    2024-04-12 13:14:02       35 阅读
  2. CSS:CSS的基础了解

    2024-04-12 13:14:02       41 阅读
  3. css Animation 动画-右进左出

    2024-04-12 13:14:02       40 阅读
  4. 实现移动端和pc端响应式css封装

    2024-04-12 13:14:02       44 阅读
  5. AWS Lab Streaming Data

    2024-04-12 13:14:02       28 阅读
  6. shell脚本每日练习

    2024-04-12 13:14:02       39 阅读
  7. Qt 无法连接MySQL数据库

    2024-04-12 13:14:02       42 阅读
  8. Objective-C学习笔记(NSDictionary,NSFileManager,Copy)4.11

    2024-04-12 13:14:02       35 阅读