1. 为什么算法会有时空复杂度
在程序设计中,为了完成某些功能,工程师们会设计一些算法,来完成这些功能。然而完成这些功能的时候不可避免的会遇到一些效率问题,而时间复杂度和空间复杂度具有算法运行时衡量算法效率的作用。
一般情况下,算法的时间复杂度与空间复杂度是成反比的,当一个算法时间复杂度降低,这个算法的空间复杂度会相应升高。二者经常不可得兼。
2. 时空复杂度的计算
时间复杂度
时间复杂度主要衡量一个算法的运行快慢。在计算机科学中,算法的时间复杂度是一个函数,它定量的描述了这个算法的运行时间。但一个算法执行所耗费的时间理论上是算不出来的,我们需要上机去测,而且受限制非常大,经常受硬件和编译器限制。一个算法的执行时间与其中语句的执行次数成正比,所以我们描述时间复杂度不用该算法的运行时间算法函数,而是用算法中的基本操作的执行次数。即
找到某条语句与问题规模N之间的表达式,就是算出了该算法的时间复杂度
如以下代码
int main()
{
int i = 0;
int sum = 0;
for (i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
sum += i * 10 + j;
}
return 0;
}
其中的代码sum += i * 10 + j; 运行了 N^2 次,那么这个代码的时间复杂度就是 O(N*N) 即 O(N²)
我们计算基本代码执行次数时不一定要精确次数只需要大概次数,这里用大O的渐进表示法。
在表示算法时间复杂度的时候我们常用最坏情况。比如如下:
int search(int src)
{
int a[N] = { 1, 2, 3, 4, 5, 6, 7, ..., N };
for (int i = 0; i < N; i++)
{
if (src == a[i])
{
return 1;
}
}
return 0;
}
这是一段遍历查找代码
此代码最好情况便是第一次直接匹配成功,那么这个代码时间复杂度是不是 O(1) 呢?或者是 O(N/2) ?还是 O(N) ?
答案是 O(N) 我们一般认为时间复杂度是算法最坏情况下的时间复杂度。
还有一种情况,当时间复杂度为常数时如:
int main()
{
int a = 10;
int b = 20;
int tmp = 0;
tmp = a;
a = b;
b = tmp;
return 0;
}
以上代码基本操作有三步,那么它的时间复杂度就是 O(1) ,而不用 O(3) 表示。
空间复杂度
空间复杂度主要用来衡量一个算法运行所需要的额外空间。在计算机发展早期,计算机的存储容量很小,所以对空间复杂度很是在乎。但计算机行业的快速发展,如今的计算机存储容量已经非常大了,我们如今不太需要特别的关注一个算法的空间复杂度。
空间复杂度也是一个数学表达式,是对一个算法在运行过程中临时占用存储空间大小的量度。空间复杂度表示的不是程序占用了多少byte的空间,这个没太大意义。空间复杂度算的时变量的个数。空间复杂度也用大O的渐进表示法表示。
空间复杂度表示的是在算法运行过程中额外申请的空间的个数就,不将算法本身的数据存储空间计算在内
表示方法也与时间复杂度类似。
如交换数值算法
算法一:
int main()
{
int a = 10;
int b = 20;
int tmp = 0;
tmp = a;
a = b;
b = tmp;
return 0;
}
算法二:
int main()
{
int a = 10;
int b = 20;
a = a ^ b;
b = a ^ b;
a = a ^ b;
return 0;
}
以上两个算法都是交换两个变量的数值,但算法一使用了一个额外变量,所以算法一的时间复杂度就是 O(1) 。 算法二无额外变量,所以算法二的时间复杂度就是 O(0)
总结
算法的时间复杂度和空间复杂度是有一些相关的,比如它们的表示非常相似,时间复杂度与空间复杂度通常成反比,二者不可得兼,所以经常有一些用空间换取时间的操作。时间复杂度与空间复杂度经常用来衡量算法的效率,并成为时空复杂度,做为程序员我们要熟练运用数据结构的专有名词。