实验分析的缺点
- 除非在相同的软硬件环境下,否则很难比较两个算法的效率
- 只能对有限的输入进行测试
- 必须完全实现的算法才能测试其性能
超越实验分析
基本操作
完美情况下,一个基本操作对应于一条具有恒定执行时间的底层指令,这样就可以通过统计基本操作的数量来估计该算法的执行时间,即找到基本操作数量与输入规模之间的函数关系 t=f(n)
以下语句通常被认为是基本操作:
7种最重要的函数关系
1. The Constant Function: f(n) = C
常数函数主要用于统计完成一个基本操作所需要的步骤数
2. The Linear Function: f(n) = n
线性函数表示一个算法能达到的最佳性能,因为读取规模为n的输入本身就需要n次操作
3. The Logarithm Function: f(n) = log n(log2 n)
常用的对数等式
4. The N-LOG-N Function: f(n) = nlogn
5. The Quadratic Function: f(n) = n^2
嵌套循环所需的操作往往是输入规模的平方
6. The Cubic Function and Other Polynomials: f(n) = n^3
7. The Exponential Function: f(n) = a^n (a>0且为常数)
关注最糟情况
虽然分析算法性能最好能够计算出该算法在同等规模输入下各种情况的平均性能,但是由于我们很难获取各种输入的分布情况,所以计算平均性能几乎是不可能的。因此我们关注于算法在最糟糕的情况下的表现,如果该算法能在最糟糕情况下表现良好,那么在其他情况下他都能表现更好
渐进分析
大O表示法
对于任意的f(n),如果存在 f(n) ≤ c g(n),在n ≥ n0(c > 0, n0 ≥ 1)时恒成立,则f(n)就是g(n)的大O表示。
大O表示法允许忽略常数因子和低阶项,只关注多项式的最高项即可。
虽然一个函数存在很多个大O表示,但是我们一般用它满足条件的最简形式来表示。
大Ω表示法
对于任意的f(n),如果存在 f(n) ≥ c g(n),在n ≥ n0(c > 0, n0 ≥ 1)时恒成立,则f(n)就是g(n)的大Ω表示。
大Θ表示法
对于任意的f(n),如果存在 c1g(n) ≤ f(n) ≤ c2 g(n),在n ≥ n0(c1 > 0, c2 > 0, n0 ≥ 1)时恒成立,则f(n)就是g(n)的大Θ表示。
一些证明方法
举例子
反向攻击法(The “Contra” Attack)
逆否命题法(contrapositive)
反证法(contradiction)
归纳法(Induction)
先证明n=1(或其他值)时命题成立;然后假设k<n时命题成立,并证明k+1命题也成立;则对于n命题也成立
循环不变量(loop invariant)
一般将循环体中的条件语句作为命题,并根据循环次数设为L(0), L(1) …L(n)
首先证明循环开始时命题成立
然后假设第k次循环开始前命题成立,证明第k次循环后命题依然成立
则说明全部循环结束后,命题也成立
以下图为例:
设置命题 L(i) : val 不等于前 i 个中元素任意一个
证明:首先,当 i = 0 时,命题显然成立
然后,假设当 i = k时,命题成立,即 前 k 个元素中,没有和 val 相同的元素。则当 i = k+1 时,若 val = S[k+1], 循环结束,返回 k+1,即正确结果;若 val ≠ S[k+1],则 val 不等于前 k+1 个中元素任意一个,即 L(k+1)成立
综上所述,当 i = n 时,L(n)也成立