在上面的文章里,我们给出了时间复杂度和空间复杂度的最小单位。
现在我们来量化描述各种算法(计算过程)的时间复杂度和空间复杂度。
如何量化时间复杂度和空间复杂度呢?
我们用时间复杂度和空间复杂度的最小单位的函数来表示。
比如,我想求 n 个整数的最大值。
空间复杂度怎么量化?
那么,我就需要 n 个内存空间来存储这 n 个整数。这时候我们就说求 n 个整数最大值的过程(算法),需要的空间复杂度为 O(n)。
时间复杂度怎么量化?
假设,这 n 个整数 连续的存储在一个数组中,那么需要的时间复杂度就是需要遍历这个 n 个整数。代码如下:
int max_num = array[0];
for(int i = 0; i < n; ++i)
{
max_num = max(max_num, array[i]);
}
return max_num;
从代码中可以看出来,我们需要读取内存 次数为 1 + n * 3。
其中, 1 对应: int max_num = array[0]; 也就是给 max_num 初始化。
其中, n * 3 对应: for(i : 0 ~ n-1) max_num = max(max_num, array[i])。 循环执行了[0~n-1] 次,也就是 n 次。
循环的每一次,访问了几次内存呢? 3 次。
为何是 3 次呢? 其实是 max_num = max(max_num, array[i]); 这条语句访问了 3 次内存。
读取 max_num 原来的值 1 次(读内存), 读取 array[i] 的值 1 次(读内存), 最后把 新的 max 求出来(这个比较是在CPU内部寄存器完成的,没有再发生内存读取),求出了 新的 max 之后 写回到内存覆盖 max_num 之前的值。 这时候 是 1 次写内存。
所以,总共是 2 次读内存, 1 次 写内存。 总共 是 3 次。
综上,求 n 个数的最大值,时间复杂度为 1 + n * 3。
由于随着 n 的规模变大, 常数 1 可以忽略。 比如, 1000000000 个整数的最大值,和 1000000001个整数的最大值,我们认为时间复杂度是相同的。
这样时间复杂度 就变成了 O(n*3) 。
另外,常数项系数,并没有从本质上改变复杂度。我们通常把常数项都改写为 1 来简化问题复杂度的描述。
这样以来,时间复杂度就变成了 O(n)。
练习:
类似的,下面的算法时间复杂度你知道是多少吗?
查询 n 个连续存放整数的 第一个元素的值 : O(1)
在 n 个连续存放的整数,而且已经按照从小大顺序排好顺序的,数组中二分查找某个值是否存在于这个数组中:O(log2(n))
在 n 行,m 列的二维数组中(假设数据连续存放)查找一个值是否存在:O(n*m)