空间复杂度的概念:一个算法在运行过程中因为算法的需要额外临时开辟的空间,我们在计算时,不是计算程序占用多少内存的空间,而是计算创建变量的个数,因为常规情况下,每个创建变量对象占用的内存空间差异不大,和时间复杂度一样,也可以用大O的渐进表示法来表示(见上篇文章),注意:函数运行时所需的栈空间(存储参数、局部变量)在编译期间已经确定好了,因此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定(形参不用统计,在编译时就已经确定了)。
示例1:
void BubbleSort(int* a, int n)
{
assert(a);
//防止a为空指针
for (size_t end = n; end > 0; --end)
{
int exchange = 0;
for (size_t i = 1; i < end; i++)
{
if (a[i - 1] > a[i])
{
swap(&a[i - 1], &a[i]);
//swap这个是交换a[i-1]和a[i]的位置
exchange = 1;
}
}
if (exchange == 0)
{
break;
//这句话是判断是否已经按照从小到大排序了,如果排序了就没必要继续循环下去了
}
}
}
可以看出来,创建了end、exchange、i这三个局部变量,所以为T(3),故为O(1),不管n变为多少,都是额外创建这三个变量。
示例2:
递归:int fac(int n)
{
if (n == 0 || n == 1)
{
return 1;
}
else
return n * fac(n - 1);
}
递归我们需要考虑最坏的情况,就是申请很多次才满足if的那个条件成立,我们最多需要申请n-1个空间,这不是创建变量,而是为了求解执行次数,和计算空间复杂度相同,结果为T(n-1),空间复杂度写为O(n)。
空间复杂度与时间复杂度的组合。
为什么要强调时间复杂度和空间复杂度的重要性?
这两者决定了之后我们写代码运行的时间空间。
我们通过一个题目来实践一下。
1.选择数组
题目链接:https://leetcode.cn/problems/rotate.array/description/
这个题目在上一个帖子里面说过,但是没有实际的解决问题的代码,这个帖子来讲一下。
我们可以把这个题目看成三次进行旋转,第一次为:前n-k个位置旋转,第二次为:后k个位置旋转,第三次为:整体旋转,三次旋转的思想需要自己去理解,之后可能会讲这种算法
如何实现?
首先,我们要有一个函数,这个函数能翻转数组
void reverse(int* arr, int begin, int end)
{
//我们要把begin和end交换位置,完了之后begin++,end--
//那这个循环的结束条件是什么呢?
//我们可以设置为begin<end
//代码如下
while (begin < end)
{
int tmp = arr[begin];
arr[begin] = arr[end];
arr[end] = tmp;
begin++;
end--;
}
}
函数如何调用?
//翻转前n-k
reverse(nums, 0, numsSize - k - 1);
//翻转后k个数据
reverse(nums, numsSize - k, numsSize - 1);
//翻转整体
reverse(nums, 0, numsSize - 1);
但是如果这样子的话,发现如果nums={-1};k=2;时,发现第一个函数的第三个传参是-2,因此我们需要改变传参的方式,故我们需要把k进行改变,我们发现,k大于numsSize,所以我们需要进行取模运算,这样才能防止传参的时候为负数,因此我们可以把函数调用之前的k变为k=k%numsSize
这样我们就可以解决这个问题了,发现时间复杂度为O(n),为什么?
T(n)=3/2*n,可以写成3*(n/2),三次调用函数,但是我们只执行了n/2次,(end-begin)/2可以把end=n,begin=0,这样算出来时间复杂度为O(n)。空间复杂度很好算,为O(1)。我们只申请了begin、end、tmp三个变量,所以为O(1)。
还有一种以空间换时间的方式来提高算法效率的方法,可以做参考,至于理解可以自己去理解一下。
void ratate(int* nums, int numsSize, int k)
{
int newArr[numsSize] = { 0 };
int i, j;
for (i = 0; i < numsSize; i++)
{
newArr[(i + k) % numsSize] = nums[i];
}
for (i = 0; i < numsSize; i++)
{
nums[i] = newArr[i];
}
}
这样算需要创建一个新的数组,导致空间复杂度变为了O(n),然后时间复杂度为O(n);空间:T(n+2);时间:O(2*n)。
空间复杂度就讲完了,下一节讲:顺序表,下节再见。
喜欢的可以一键三连哦。