这一节我们主要来讨论空间复杂度。
空间复杂度:是对占用空间大小的度量。
对于考研、大学课程考试中,对空间复杂度的考察一般都较少,总体来说,理解了时间复杂度也便对空间复杂度有了一定的掌握。
我们所讨论的空间复杂度,要抛开计算机运行的机制来看,不要去细扣到底是占用的内存、缓存还是虚拟内存甚至外存,不要去考虑这些存储器在取用数据所耗费的时间,但但通过程序来说明所去占用的空间大小。
时间复杂度和空间复杂度有时是能够相互转化的,在实际应用中,可以牺牲空间来提升时间,当然,也可以通过牺牲时间来换取空间,计算机的操作系统设计有时就是在找这个平衡点,确保计算机最大的利用率。
空间复杂度的计算公式可以记为:S(n) = O(f(n))。
在《趣学算法(第二版)》中有两个关于空间复杂度的例子比较经典,不如我们就借鉴这两个例子来理解空间复杂度。
先看一个x与y进行数值交换的例子:
void swap(int x,int y){
int temp;
temp = x;
x = y;
y = temp;
}
(插一句,图画的实在是不好,辛苦大家将就看吧,我要再学学如何画更好看的图片)这个顺序是不能够改变的,或者说,不能够箭头同时向外指向,把箭头方向顺时针转,变化1,2,3的顺序,也是能够实现相应功能的,我们看到,我们使用了一个空间temp,因此,空间复杂度为O(1)。
我们再来看第二段代码:
int fac(int n){
if(n==0||n==1)
return 1;
else
return n*fac(n-1);
}
这是一个计算n的阶乘的代码,用到了递归的思想,递归包括了递推和回归两个步骤,递推是将原来的问题不断地分解,直到满足条件停止,进行回归的步骤,通过一步步的回归,达到解决问题的目的。
我们分别来看,以n=5为例:
递推的过程:5*fac(4)——>4*fac(3) ——>3*fac(2)——> 2*fac(1)——> fac(1)
回归的过程:fac(1)=1——>2*fac(1)=2——> 3*fac(2)=6——> 4*fac(3)=24——> 5*fac(4)=120
用“栈”(后进先出)图来表示为:
进栈 |
5*fac(4) |
进栈 |
4*fac(3) |
5*fac(4) |
进栈 |
3*fac(2) |
4*fac(3) |
5*fac(4) |
进栈 |
2*fac(1) |
3*fac(2) |
4*fac(3) |
5*fac(4) |
进栈 |
fac(1) |
2*fac(1) |
3*fac(2) |
4*fac(3) |
5*fac(4) |
以上便是5的阶乘的进栈过程,出栈便是以上表格的逆序过程。
我们看到,n是多大,占用的空间就是多大,因此,这个程序的空间复杂度为O(n)。空间复杂度的计算就是通过占用空间来计算的。
我们通过阶乘也看一看到,使用递归的方法来计算问题是,可能会出现占用空间非常大的情况,当数值特别大,占用了全部的内存空间,那必然导致了计算机的死机,无法得出正确的结果,因此,日常在设计程序时,应该尽量避免使用递归的方法设计较大的程序,避免运行时资源被占用。
以上便是对程序复杂度的基本度量方法,下一节,将带大家学习一个基础知识,伪代码,伪代码将在以后的学习中经常用到,先要学习打好基础,以方便以后的学习。