接上一篇[数据结构](1)时间复杂度详解_CegghnnoR的博客-CSDN博客
接下来学习空间复杂度。
空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大小的量度,记做 S ( n ) = O ( f ( n ) ) S(n)=O(f(n)) S(n)=O(f(n))
首先,空间复杂度不是程序本身(可执行程序文件)的大小,而是程序运行时占用内存空间的大小
空间复杂度的计算与时间复杂度类似,也使用大O渐进表示法。
空间复杂度的计算相对来说比较简单,下面直接上例子:
void bubble(int* arr, int sz) {
int i, j, tmp;
for (i = 0; i < sz - 1; i++) {
for (j = 0; j < sz - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
不算arr
数组的空间,因为它不是我们这个算法开辟出来的。
那么这个算法的空间复杂度为 O ( 1 ) O(1) O(1),因为只开辟常数个额外空间,它所开辟的空间并不会随arr
大小的变化而变化。
long long* Fibonacci(size_t n) {
if (n == 0)
return NULL;
long long* fibArray = (long long*)malloc((n + 1) * sizeof(long long));
fibArray[0] = 0;
fibArray[1] = 1;
for (int i = 2; i <= n; ++i) {
fibArray[i] = fibArray[i - 1] + fibArray[i - 2];
}
return fibArray;
}
计算斐波那契数列的前n
项,并存入一个数组里,
随n
的增大,fibArray
空间也会随之增大,呈线性关系,所以空间复杂度为 O ( n ) O(n) O(n)
递归的空间复杂度 = 递归的深度 * 每次递归的空间复杂度
注意和时间复杂度的计算不同,这里是深度而不是次数。因为时间不可以重复利用,而空间可以。
具体请看例子:
long long Fac(size_t N) {
if (N == 0)
return 1;
return Fac(N - 1) * N;
}
递归求阶乘。
每次递归都会开辟1个栈帧压到调用栈里,栈的原理就是先进后出,后进先出。最大深度就是栈的深度。
算法递归调用了N次,开辟了N个栈帧,每个栈帧使用常数个空间,空间复杂度为 O ( n ) O(n) O(n)
int Fib(int N) {
if (N < 3)
return 1;
return Fib(N - 1) + Fib(N - 2);
}
递归计算斐波那契数列。
按照程序运行顺序,依次将f(5)f(4)f(3)f(2)压入栈中,然后f(2)弹出,f(1)又会补上,f(1)f(3)弹出,f(2)进入 ⋯ ⋯ \cdots\cdots ⋯⋯
最大深度为5。求第n位的话,最大深度就是n。每次递归的占用常数个空间
所以空间复杂度为 O ( n ) O(n) O(n)
上一篇分析了二分查找的时间复杂度为 O ( log n ) O(\log n) O(logn),那是非递归版本的,空间复杂度应是 O ( 1 ) O(1) O(1),
那么其递归实现的空间复杂度是多少呢?
int binarySearch(int arr[], int l, int r, int x) {
if (r >= l) {
int mid = l + (r - l) / 2;
if (arr[mid] == x)
return mid;
if (arr[mid] > x)
return binarySearch(arr, l, mid - 1, x);
return binarySearch(arr, mid + 1, r, x);
}
return -1;
}
每次递归占用常数个空间。注意这里传的是数组的地址,每次递归不会创建新的数组。
二分查找的执行次数是 x = log 2 n x=\log_2n x=log2n,和这里的递归深度一样。
所以空间复杂度为 O ( log n ) O(\log n) O(logn)
算法性能分析到此结束,可以说还是比较全面的,把各种经典例子分析了一遍,希望能有更深刻的理解。
如果对你有帮助的话,希望能多多支持,三连一下~