【数据结构】空间复杂度

目录

1.空间复杂度

2.空间复杂度使用例


1.空间复杂度

本章内容要分享的是空间复杂度,空间复杂度也是一个数学表达式,是对一个算法在运行过程中临时占用存储空间大小的量度 。


空间复杂度不是程序占用了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数

空间复杂度计算规则基本跟实践复杂度类似,也使用大O渐进表示法。


注意:函数运行时所需要的栈空间(存储参数、局部变量、一些寄存器信息等)在编译期间已经确定好了,因此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定。

废话不多说直接看代码来探讨

2.空间复杂度使用例

实例1

void BubbleSort(int* a, int n)
	{
		assert(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]);
					exchange = 1;
				}
			}
			if (exchange == 0)
				break;
		}
	}

以上是冒泡排序的代码,我们是否能看出他的空间复杂度呢?

这里不难看出开辟了三个空间,分别是exchange、end、i,这些都是常数个变量,那么空间复杂度就是O(1)

上面的概念有提到,空间复杂度计算的是申请的额外的空间,其实这些数组的排序并不能算作是空间的消耗。我们也可以理解为冒泡排序的算法只是对已经有的数据进行处理,将其排序,将它看作一种处理数据的手段,并不需要额外的消耗空间 ,所以它的空间复杂度就是O(1)。

实例2

继续观察斐波那契的空间复杂度

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;
	}

和前面所学的斐波那契不同的是这里用malloc直接申请了一块空间

我们申请了一块大小为n+1*类型大小的数组,同样的计算他的估值,不难看出他的空间复杂度就是O(N)

实例3

继续观察递归函数的空间复杂度

long long Fac(size_t N)
	{
		if (N == 0)
			return 1;
		return Fac(N - 1) * N;
	}

在函数递归时会建立栈帧,用图例可能会便于理解

【数据结构】空间复杂度_第1张图片

 我们可以看到函数再每一次调用时都会建立栈帧然后继续往下调用,直到调用到Fac(1),才一层一层的返回,所以一共开辟了N个空间,所以空间复杂度就是O(N)

实例4

继续加一点难度,观察下面的空间复杂度是多少

long long Fib(size_t N)
	{
		if (N < 3)
			return 1;
		return Fib(N - 1) + Fib(N - 2);
	}

 数据结构画图理解题意是必不可少的,我们不妨继续画图理解

【数据结构】空间复杂度_第2张图片

像这样的函数递归的在调用栈帧时是一直直着向下调用的,也就是说从Fib(N)进去后会调用Fib(N-1),之后会向下调用Fib(N-2),之后会向下调用Fib(N-3),以此类推最终调用到Fib(1)的时候再去调用其他列的函数,就类似于以下这种情况

【数据结构】空间复杂度_第3张图片

 先将一个调用到最深,再调用别的函数和之前的函数递归共用同一块栈帧,重复使用。

也就是说在研究递归的空间复杂度时我们只用研究他的深度即可。

那既然是重复使用着一块空间,我们不妨就理解为只用了红框中的那一部分空间,所以他的空间复杂度为O(N)

所以根据这两篇的内容我们可以知道时间是一去不复返的,但空间是可以重复利用的。

空间复杂度的内容不是非常困难,如果文章对你有所帮助,不妨三联支持以下,感谢阅读。

你可能感兴趣的:(数据结构,算法,c语言,空间复杂度,开发语言)