文章目录
-
- 前言
- 一、什么是空间复杂度?
- 二、空间复杂度的数学定义
- 三、常见空间复杂度举例(含C语言代码)
-
- [🔹 O(1):常数空间](#🔹 O(1):常数空间)
- [🔹 O(n):线性空间](#🔹 O(n):线性空间)
- [🔹 O(n^2):平方空间](#🔹 O(n^2):平方空间)
- 四、输入数据占用的空间算吗?
- 五、递归中的空间复杂度
- [六、时间复杂度 vs 空间复杂度](#六、时间复杂度 vs 空间复杂度)
- 七、优化空间复杂度的常见方法
- 总结
前言
当你写出一段能"跑得起来"的C语言程序时,也许你会觉得:"OK,搞定了!"
但你有没有想过:
- 这段程序在处理大数据量时,会不会把内存撑爆?
- 有没有可能用了太多没必要的变量和数组,浪费了资源?
- 如果要在嵌入式系统或内存有限的设备上跑,它还能正常运行吗?
这时,我们就得引入另一个重要的概念 ------ 空间复杂度(Space Complexity)。
空间复杂度,简单来说,就是分析你的程序到底"吃"了多少内存。它不仅能帮助我们优化程序效率,也能避免内存泄漏、程序崩溃等一系列问题。
一、什么是空间复杂度?
在学习编程时,我们经常关心程序运行的速度,而空间复杂度关注的则是程序运行时**"占用了多少内存"**。
举个例子:
如果你写了一个程序,它在处理数据时需要开辟额外的数组、结构体、变量等存储信息,那么这些就算作了额外空间。空间复杂度就是用来衡量这部分空间使用情况的。
通俗理解:
你可以把程序比作一个人在做题:
- 他眼前的试卷是输入数据(这些不算在空间复杂度里)
- 他额外准备的草稿纸、笔、计算器就是辅助空间(这些要算)
空间复杂度,关注的就是:这个人需要准备多少张草稿纸?
二、空间复杂度的数学定义
空间复杂度一般用大写的 O 符号表示,例如:
O(1)
:常数空间,只用很少的变量O(n)
:线性空间,比如要开一个数组来存储 n 个元素O(n^2)
:平方空间,常见于二维数组或矩阵问题
我们不关心精确的字节数,只看输入规模 n 增加时,额外内存的增长趋势。
三、常见空间复杂度举例(含C语言代码)
🔹 O(1):常数空间
程序只用固定几个变量,不随输入变化而变化。
c
int max(int arr[], int n) {
int maxVal = arr[0];
for (int i = 1; i < n; i++) {
if (arr[i] > maxVal) {
maxVal = arr[i];
}
}
return maxVal;
}
分析:
maxVal
和i
是两个变量,和n
的大小无关- 所以空间复杂度是
O(1)
🔹 O(n):线性空间
程序根据输入的大小,分配了等量的内存空间。
c
int* duplicate(int arr[], int n) {
int* result = (int*)malloc(n * sizeof(int));
for (int i = 0; i < n; i++) {
result[i] = arr[i];
}
return result;
}
分析:
- 申请了一个新的数组
result
,长度为n
- 所以空间复杂度为
O(n)
🔹 O(n^2):平方空间
使用了二维数组,如矩阵、图的邻接矩阵等情况。
c
int** createMatrix(int n) {
int** matrix = (int**)malloc(n * sizeof(int*));
for (int i = 0; i < n; i++) {
matrix[i] = (int*)malloc(n * sizeof(int));
}
return matrix;
}
分析:
- 共申请了
n × n
个整数的空间 - 所以空间复杂度为
O(n^2)
四、输入数据占用的空间算吗?
不算!
空间复杂度只考虑算法运行过程中新增的内存。输入数据(比如函数参数)默认已经存在,不属于算法"额外使用"的空间。
五、递归中的空间复杂度
递归函数往往会消耗较多空间,因为每一次递归调用都会压入一个栈帧。
c
int factorial(int n) {
if (n == 1) return 1;
return n * factorial(n - 1);
}
分析:
- 递归深度为
n
,每次调用都占一份栈空间 - 所以空间复杂度为
O(n)
六、时间复杂度 vs 空间复杂度
对比项 | 时间复杂度 | 空间复杂度 |
---|---|---|
含义 | 程序运行需要的"时间" | 程序运行需要的"空间" |
衡量单位 | 步数(操作次数) | 字节数/变量个数等 |
关注点 | 程序快不快 | 程序占不占内存 |
示例 | 排序算法耗时 | 哈希表占用内存 |
有时需要做取舍,比如:
- 用 更多空间 来加快处理速度(空间换时间)
- 用 更少空间,但处理得慢一些(时间换空间)
七、优化空间复杂度的常见方法
方法 | 举例说明 |
---|---|
尽量复用变量 | 不重复创建数组 |
能用原地修改就原地修改 | 冒泡排序直接在原数组上操作 |
使用位运算压缩空间 | 布尔数组压缩成位图(bitset) |
及时释放动态内存 | 使用 free() 释放 malloc() 空间 |
总结
- 空间复杂度衡量的是程序运行时占用的额外内存大小
- 通常只考虑临时变量、辅助数组、递归栈帧等
- 表达形式用
O(1)
、O(n)
、O(n^2)
等 - 递归和大数据处理时要特别注意空间使用
- 编程中要学会在时间与空间之间做平衡