数据结构 算法空间复杂度分析
空间复杂度,衡量内存开销与问题规模 n 之间的关系,和时间复杂度共同构成算法效率的度量。
定义
空间复杂度:用于量度一个算法运行过程中临时占用的存储空间大小。
重要考点:只算辅助变量,不算输入数据本身所占的空间!
一般也作为问题规模n的函数,采用数量级形式描述,记作:
S(n)=O(g(n))
- 若一个算法的空间复杂度为 O(1),则称此算法为原地工作 / 就地工作算法 。
注意:O(1)不是完全不用空间,而是辅助空间大小和 n 无关,是固定常量。不是零空间!
一、普通非递归程序的分析方法
步骤:
- 找出辅助变量、动态数组中,大小会随 n 变化的变量。输入参数不算!
- 分析该空间 x 和 n 的关系:x=f(n)
- 取数量级,得到 S(n)=O(f(n))。
小口诀:静态变量不算数,输入数组不算数,只看临时新开的。
示例1:O(1) 原地算法
c
void loveYou(int n)
{
int i=1;
while(i<=n)
{
i++;
printf("I Love You %d\n", i);
}
printf("I Love You More Than %d\n", n);
}
分析:变量 i 是固定单个变量,数量不随 n 变化。
👉 空间复杂度:S(n)=O(1)。
c
int fun(int n)
{
int i, j, k, s;
s=0;
for (i=0;i<=n;i++)
for(j=0;j<=i;j++)
for (k=0;k<=j;k++)
s++;
return(s);
}
分析:所有变量都是固定数量,循环只是执行次数变化,没有动态开辟数组。
👉 空间复杂度:S(n)=O(1)。
示例2:O(n),一维动态数组
c
void test(int n)
{
int flag[n]; // 长度为n的数组
int i;
// ...省略代码
}
分析:数组 flag 的大小等于 n,辅助空间随 n 线性增长。
👉 空间复杂度:S(n)=O(n)。
示例3:O(n²),二维动态数组
c
void test(int n)
{
int flag[n][n]; // n×n二维数组
int i;
// ...省略代码
}
👉 空间复杂度:S(n)=O(n²)。
多个数组叠加时,使用加法规则:O(f(n))+O(g(n))=O(max(f(n),g(n)))
例:同时有 flagnn 和 othern,S(n)=O(n2)+O(n)=O(n2),只保留最高阶。
一般关于数组:一旦形参涉及到数组
eg:imn O(n)=n 一维数组
imnn O(n)=n^2 二维数组
二、递归程序的分析方法
递归的空间复杂度 = 递归调用的最大深度!
每一层递归,栈上都会保存一层局部变量与参数。栈帧深度决定空间。
示例1:深度为 n 的递归
c
void loveYou(int n)
{
int a,b,c;
if (n > 1) {
loveYou(n-1);
}
printf("I Love You %d\n", n);
}
分析:调用链 loveYou(5) → loveYou(4) → ... → loveYou(1),递归深度 = n。
👉 空间复杂度:S(n)=O(n)。
示例2:每层递归再开一个数组
c
void loveYou(int n)
{
int flag[n];
if (n > 1) {
loveYou(n-1);
}
printf("I Love You %d\n", n);
}
分析:第n层开n个、n‑1层开n‑1个......总和 1+2+...+n≈\frac12 n^2。
👉 空间复杂度:S(n)=O(n²)。
⚠️ 坑点:不是只看单层,要累加整个递归栈的空间!
三、复杂度运算规则
- 加法规则:O(f(n)) + O(g(n)) = O(max(f(n),g(n)))
- 乘法规则:O(f(n)) × O(g(n)) = O(f(n)×g(n))
完整大小顺序(时间、空间通用):
O(1) < O(log₂n) < O(n) < O(nlog₂n) < O(n²) < O(n³) < O(2ⁿ) < O(n!) < O(nⁿ)
四、经典例题
例题1
算法的空间复杂度是指()。
A.算法中输入数据所占用的存储空间的大小
B.算法本身所占用的存储空间的大小
C.算法中所占用的所有存储空间的大小
D.算法中需要的辅助变量所占用存储空间的大小
答案:D
解析:输入数据的空间不计入空间复杂度。
例题2
某算法的空间复杂度为O(1),则()。
A.该算法执行不需要任何辅助空间
B.该算法执行所需辅助空间大小与问题规模n无关
C.该算法执行不需要任何空间
D.该算法执行所需空间大小与问题规模n无关
答案:B
解析:只针对辅助空间,不是全部空间。
例题3【判断题】
一个算法的空间复杂度是O(1),那么执行该算法时不需要任何空间。
答案:错
O(1)代表辅助空间是常量,仍然会用到少量变量空间,不是零。
五、空间复杂度做题通用步骤
- 区分输入与辅助:输入数组不算!只看算法自己临时开辟的变量、数组。
- 非递归:看动态数组的维度,一维O(n),二维O(n²),没有动态数组大多O(1)。
- 递归:找递归深度! 深度是多少,阶就是多少;每层还开数组,需要累加计算。
- 最后:忽略常数、系数、低阶项,保留最高阶得到大O。
背诵总结
-
空间复杂度只统计辅助存储空间,输入数据所占空间不计入。
-
O(1)=原地算法:辅助空间是固定常量,不是完全不用空间。
-
普通程序:看动态数组;递归程序:空间复杂度主要由递归深度决定。
-
复杂度排序:O(1) < O(log₂n) < O(n) < O(nlog₂n) < O(n²) < O(n³) < O(2ⁿ)。