复杂度分析:
1. 时间复杂度分析:
代码执行时间随数据规模增长的变化趋势, 也叫作渐进时间复杂度,简称时间复杂度。T(n) = O(f(n))
(1) 我们在分析一个算法、一段代码的时间复杂度的时候,也只关注循环执行次数最多的那一段代码就可以了。这段核心代码执行次数的 n 的量级,就是整段要分析代码的时间复杂度。
(2) 加法法则:总复杂度等于量级最大的那段代码的复杂度.
(3) 乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积.
时间复杂度的大 O 标记法中,可以省略掉系数、低阶、常量。
一般情况下,只要算法中不存在循环语句、递归语句,即使有成千上万行的代码,其时间复杂度也是Ο(1)
2. 空间复杂度分析:
空间复杂度全称就是渐进空间复杂度,表示算法的存储空间与数据规模之间的增长关系。
常见的复杂度并不多,从低阶到高阶有:O(1)、O(logn)、O(n)、O(nlogn)、O(n )。几乎所有的数据结构和算法的复杂度都跑不出这几个。
3. 最好情况时间复杂度、最坏情况时间复杂度、平均情况时间复杂度、均摊时间复杂度
(1)最好、最坏情况时间复杂度, 例如:
这段代码要实现的功能是,在一个无序的数组(array)中,查找变量x 出现的位置。如果没有找到,就返回 -1。
n代表数组的长度, 按照上面的大O分析方法:
(最好情况时间复杂度)
(最坏情况时间复杂度)
所以,不同的情况下,这段代码的时间复杂度是不一样的。
最好情况时间复杂度: 在最理想的情况下,执行这段代码的时间复杂度。
最坏情况时间复杂度: 在最糟糕的情况下,执行这段代码的时间复杂度。
借助刚才查找变量 x 的例子,要查找的变量 x 在数组中的位置,有 n+1 种情况:
在数组的 0~n-1 位置中和不在数组中。我们把每种情况下,查找需要遍历的元素个数累加起来,然后再除以 n+1,就可以得到需要遍历的元素个数的平均值,即:
从概率的角度分析,要查找的变量 x,要么在数组里,要么就不在数组里。这两种情况对应的概率统计起来很麻烦,为了方便你理解,我们假设在数组中与不在数组中的概率都为 1/2。
另外,要查找的数据出现在 0~n-1 这 n 个位置的概率也是一样的,为 1/n。
所以,根据概率乘法法则,要查找的数据出现在 0~n-1 中任意位置的概率就是 1/(2n)。
平均时间复杂度的计算过程就变成了这样:
这个值就是概率论中的加权平均值,也叫作期望值,所以平均时间复杂度的全称应该叫加权平均时间复杂度或者期望时间复杂度。
引入概率之后,前面那段代码的加权平均值为 (3n+1)/4。用大 O 表示法来表示,去掉系数和常量,这段代码的加权平均时间复杂度仍然是 O(n)。
实际上,在大多数情况下,我们并不需要区分最好、最坏、平均情况时间复杂度三种情况。
很多时候,我们使用一个复杂度就可以满足需求了。
只有同一块代码在不同的情况下,时间复杂度有量级的差距,我们才会使用这三种复杂度表示法来区分。
4. 均摊时间复杂度(摊还分析法)
均摊时间复杂度就是一种特殊的平均时间复杂度