【久远讲算法】 什么是空间复杂度

你好,我是久远,这周我们继续聊算法,接着上次的时间复杂度,我们进行关于空间复杂度的讲解。

知识回顾

首先,我们来对上周的任务进行大概的复习。

算法是什么?

  • 从理论层面来讲,算法就是我们写程序写代码的优化手册,它教会我们怎么让代码运行起来更快,或者占用的内存空间更少。直观层面来讲便是,算法是一系列程序指令,用于处理特定的运算和逻辑问题。一个算法是好是坏,我们通常根据时间复杂度和空间复杂度去评价。

时间复杂度是什么?

  • 时间复杂度是对一个算法运行时间长短的量度,用大 O 表示,常见的时间复杂度按照从低到高的顺序,包括O(1)、O(logn)、O(n)、O(nlogn)、O(n^2) 等。

时间复杂度的要点包括以下内容:

  • 基本操作执行次数。即每行代码的执行次数,我们通过这个来计算我们所写的代码详细的执行次数。
  • 渐进时间复杂度。计算基本操作执行次数固然是一种求解时间复杂度的方法,但是我们平时写的代码是千奇百怪的,因此通过计算基本操作执行次数得到的数字或函数大多都比较复杂,并不适合直接充当我们的时间复杂度,因此我们引入了渐进时间复杂度的概念,渐进时间复杂度常用大 O 符号表述,不包括这个函数的低阶项和首项系数。使用渐进时间复杂度可保证我们算出的时间复杂度函数相比起基本执行操作次数总和更加简洁。

空间复杂度和时间复杂度的关系

空间复杂度和时间复杂度,这两个东西长得非常的像,但到底有什么区别呢?

从文字的角度,我们可以联想到,时间一般是我们摸不着的,比较抽象的东西。而空间一般是现实存在的,我们能摸到的,比较具体的东西。

再从平常我们思考的角度讲,我们去分析一件事情,一般要从理论和实际两种层面上进行分析。比如我想去旅游,理论上我只要有钱,有时间,我就可以出去旅游。但是从现实的层面去考虑这件事就很繁琐,我们要想到:当前季节上是否适合旅游,自己是否要先向学校或者上班的地方请假报备,然后再考虑订哪天的机票,以及目的地的选取等等琐事。

编程也并不是一件虚拟的事情,它是切实存在且在生活中被频繁使用的,因此我们有必要从理论和实际两种方面考虑自己所写的代码的可行性。

时间复杂度就是我们对自己代码的“理论分析”。从我们个人编程的角度而言,我们的代码仅用于个人电脑使用,并不参与企业开发,所以我们一般不去考虑计算机的性能。单纯的考虑了,怎么写这段代码,它不会出错,可以正确执行。在进行数据结构和算法的学习之后,我们慢慢的开始考虑自己代码的时间复杂度。即如何让自己写的代码运行速度的更快一些。

空间复杂度便是我们对自己代码的“实际分析”。可能我们个人写代码体会不到空间复杂度的重要性。假设你在大型企业上班,你的老板要求你开发一个手机应用,这个时候,我们要考虑的就不仅仅是,我写的代码能不能正常运行起来这件事了,因为你要站在用户的角度去考虑,你的体验度是怎么样的,作为手机应用的使用者,我们自然会想到,我希望这个手机应用能够秒开,而不是点进去半天才能加载出来,同时也希望这个手机应用占手机的内存少一点。而作为老板,让员工开发应用的时候,也希望公司提供的电脑能安全完成开发,不希望出现因为代码运行时间过长而消耗电脑硬件,导致电脑坏掉拖延项目进展的事情发生。

空间复杂度有着类似于时间复杂度的概念:一个算法或程序的空间复杂度定性地描述该算法或程序运行所需要的存储空间大小。空间复杂度是相应计算问题的输入值的长度的函数,它表示一个算法完全执行所需要的存储空间大小。

和时间复杂度类似,空间复杂度通常也使用大 O 记号来渐进地表示,即空间复杂度也有渐进空间复杂度一说。例如O(n)O(nlogn)O(n^α)O(2^n) 等;其中 n 用来表示输入的长度,该值可以影响算法的空间复杂度。

就像时间复杂度的计算不考虑算法所使用的空间大小一样,空间复杂度也不考虑算法运行需要的时间长短。

空间复杂度

从整个程序来讨论的话,程序的空间复杂度可以完全用程序代码本身所占用的存储空间多少来表示。

首先,程序自身所占用的存储空间取决于其包含的代码量,我们只要在编程环境下输入代码进行运行,那么这段代码必定会占用电脑的存储空间。想要压缩这部分存储空间,就要求我们在实现功能的同时,尽可能编写足够短的代码,但从这一方面来讲,过于庞大,毕竟我们编写一段代码,其中包含着很多内容,我们将继续将代码拆分分析为以下两种情况去推算空间复杂度。

一般一段代码的空间复杂度涉及到的空间类型有:

1..输入、输出空间。程序中如果需要输入输出数据,也会占用一定的存储空间。程序运行过程中输入输出的数据,往往由要解决的问题而定,即便所用算法不同,程序输入输出所占用的存储空间也是相近的。即,无论是我们使用 10 行代码还是三行代码去实现同一个问题,他们最终输出的东西一样的话,即使二者代码长度不尽相同,但是输出所占的存储空间是差不多大的。

2..暂存空间。程序在运行过程中,可能还需要临时申请更多的存储空间。事实上,对算法的空间复杂度影响最大的,往往是程序运行过程中所申请的临时存储空间。不同的算法所编写出的程序,其运行时申请的临时存储空间通常会有较大不同。

通常情况下,空间复杂度指在输入数据大小为 N 时,算法运行所使用的「暂存空间」+「输出空间」的总体大小。

先来看几种常见的空间复杂度。我们根据代码来进行详细分析。

常量空间

当算法的存储空间大小固定,和输入规模没有直接的关系时,空间复杂度记作 O(n) .

void fun1(int n){
    int var = 3;
    ...
}
def fun1(n):
    var = 3
    ...

讲解 python 代码:

我们定义了 fun1()函数,当我们调用这个函数的时候,我们要向其中传入一个参数 n ,但是n传入后,函数 fun1()做了一件事,它里层引入了一个 var 变量 并给它赋值 3 ,但这一切并没有改变我们输入的参数 n 的值和类型。根据上文第二条 “ 程序中如果需要输入输出数据,也会占用一定的存储空间 ”,我们输入的参数 n 从头至尾没有发生改变,因此程序所占的存储空间也没有发生改变。所以该程序的空间复杂度为 O(1) .

线性空间

当算法分配的空间是一个线性的集合(如列表或数组),并且集合大小和输入规模 n 成正比时,空间复杂度记作O(n) .

void fun2(int n){
    int[] array = new int[n];
    ...
}
def fun2(n:int):
    array_list = [for x in range(1,n)]
    ...

讲解 python 代码:

我们定义了 fun2()函数,当我们调用这个函数的时候,我们向其中传入一个参数 n ,参数 n 的类型为 int (整数类型),然后 n 被传入后,函数 fun2()利用 n 做了一件事:定义了一个长度为 n ,元素为从1到 n 的列表 array_list 。我们本来的输入规模为 n ,由上文中“ 程序在运行过程中,可能还需要临时申请更多的存储空间 ”可知,在函数内我们引入了长度为 n 的列表。即在这个程序中,我们额外申请了 n 长度的一维列表,与输入规模 n 成正比,所以该程序的空间复杂度记为 O(n).

二维空间

当算法分配的空间是一个二维列表或数组集合,并且集合的长度和宽度都与输入规模 n 成正比时,空间复杂度记作 O(n^2).

void fun3(int n){
    int[][] matrix = new int[n][n];
    ...
}
def fun3(n:int):
    matrix_list = []
    for i in range(n):
        matrix_list.append([0]*n)
    ...

对 python 代码进行讲解:

我们新建了一个函数fun3() ,它的目的是新建一个 n×n 的二维列表,我们的做法是:首先新建一个空的列表 matrix_list 然后对 matrix_list 进行一维列表的迭代和添加,最后生成二维列表。首先我们从生成一维列表开始,将n 传入 fun3() 中,我们首先新建一个空列表,为之后向列表中添加元素做准备,然后我们要稍微动一下脑子,当新建一个长度为 n 元素全为 0 的一维列表时,我们使用了循环来进行列表的初始化,所以在新建二维列表时,我们可以用类似的方法,同样使用循环来进行初始化,在一维列表初始化过程中,我们是不是将0元素挨个添加到列表中,以实现有 n 个 0 的列表,那现在我们要生成拥有 n×n 个 0 的列表,那是不是将[0] 做 n 次循环添加到 matrix_list 中就可以了。然后我们根据“ 程序在运行过程中,可能还需要临时申请更多的存储空间。”这一点可知,我们传入的参数 n 与二维列表 n×n 的长度成正比。所以该代码空间复杂度即为O(n^2).

以下我们使用了当 n 为2时的情况,进行了函数模拟。

递归空间

程序调用函数是基于栈实现的,函数在调用期间,引入一个栈并进行入栈操作,将调用来的函数以及其参数信息全都压入栈中,当函数进行 return 操作时,执行出栈操作,把上一次调用的函数和参数信息从栈中弹出。从而释放掉多余的内存。

int fun4(int N){
    if(N <= 1){
        return 1;
    }
    return fun4(N - 1) + 1;
}
def fun4(N:int):
    if N <= 1: return 1
    return fun4(N - 1) + 1

对 python 代码进行分析:

当我们输入的 $N 流沙团队联合AI悦创|久远·推出辅导班啦,包括「Python 语言辅导班、C++ 辅导班、java 辅导班、算法/数据结构辅导班、少儿编程、pygame 游戏开发」,全部都是一对一教学:一对一辅导 + 一对一答疑 + 布置作业 + 项目实践等。QQ、微信在线,随时响应!

AI悦创·推出辅导班啦,包括「Python 语言辅导班、C++辅导班、算法/数据结构辅导班、少儿编程、pygame 游戏开发」,全部都是一对一教学:一对一辅导 + 一对一答疑 + 布置作业 + 项目实践等。QQ、微信在线,随时响应!V:Jiabcdefh
AI悦创 » 【久远讲算法】 什么是空间复杂度

发表评论