第二章 算法分析

第二章 算法分析

讨论:

  1. 如何估计一个程序所需要的时间
  2. 如何将一个程序的运行时间从天或年降低到秒
  3. 粗心地使用递归的后果
  4. 将一个数自乘得到其幂以及计算两个数的最大公因数的非常有效的方法

    数学基础

函数间建立一种相对的级别:

定义1:如果存在正常数c和n0使得当N>=n0时 T(N)<=cf(N),则记T(N)=O(f(N)).

理解:T(N)增长率小于f(N). 念"大O"

定义2:如果存在正常数c和n0使得当N>=n0时 T(N)>=cf(N),则记T(N)=Ω(f(N)).

        理解:T(N)增长率大于f(N).

定义3:T(N)=Θ(h(N))当且仅当T(N)=O(h(N))且T(N)=Ω(f(N))。

        理解:T(N)增长率等于f(N)

定义4:如果T(N)=O(p(N))且T(N)≠T(N)=Θ(p(N)),则T(N)=o(p(N))。

        理解:T(N)增长率小于p(N). 念"小o"。不存在T(N)=p(N)情况

相对增长率(relative rate of growth):给定两个函数,通常存在一些点,在这些点上一个函数的值小于另一个函数的值,因此,像f(N)<g(N)这样申明没有意义。

重要结论:

法则1:T1(N)=O(f(N))且T2(N)=O(g(N)),那么

  1. T1(N)+T2(N)=max(O(f(N)), O(g(N))),
  2. T1(N)*T2(N)=O(f(N)* g(N))

法则2:如果T(N)是一个k次多项式,则T(N)=Θ(N^k)

法则3:对任意常数k,对数增长非常缓慢

注意:

  1. 常数和低阶项不要放入大O。
  2. 我们总能通过计算极限来确定两个函数f(N)和g(N)的相对增长率,必要的时候可以使用 洛必达法则

该极限有四种可能的值:

极限0:这意味着f(N)=o(g(N))。

极限是c≠0:这意味着f(N)=Θ(g(N))。

极限是∞:这意味着g(N)=o(f(N))。

极限摆动:二者无关

模型

在正式的框架中分析算法,我们需要一个计算模型。

要分析的问题-运行时间

数据输入的数量是注意考虑方面,计算算法所花费的平均运行时间和最坏情况下的运行时间。一般来说,若无相反的指定,则所需要的量是最坏情况下的运行时间。

1、对于小输入没必要去设计聪明的算法

2、数据的读入有时会比算法运行时间来长

运行时间计算

约定:不存在特定的时间单位。因此我们抛弃一些常数系数,只计算大O

一个简单的例子

没有必要计算每一行所花的时间。

一般法则

法则1-for循环:

一次for循环的运行时间至多是该for循环内语句(包括测试)的运行时间乘以迭代次数。增长率为O(N)

法则2-嵌套的for循环:

从里向外分析,在嵌套循环内部的一条语句总的运行时间是该语句的运行时间乘以该组所有的for循环的大小的乘积。如果每个for循环的大小都为N,那么增长率为O(N^k)(k为嵌套循环的个数)

法则3-顺序语句:

将各个语句的运行时间求和即可(其中总开销是增长率最高的项)

法则4-if/else语句

对于

if(condition)

        S1

    Else

        S2

一个if/else语句的运行时间从不超过判断再加上S1和S2中运行时间长者的总的运行时间

递归调用运行时间分析:

例子long int Fib(int N)

{

    If(N<=1)

        Return 1;

    Else

        Return Fib(N-1)+Fib(N-2);

}

设Fib(N)运行时间为T(N),则

T(N)=T(N-1)+T(N-2)+2;

 

最大子序列和问题的解

分治策略:

分:把问题分成两个大致相等的子问题,进行递归分解

治:"治"阶段将两个子问题的解合并到一起并可能再做些少量附加工作,最后得到问题的解。

联机算法:

只对数据扫描一次,在任意时刻,算法都能对它已经读入的数据给出子序列问题的正确答案。仅需要常量空间并以线性时间运行的联机算法几乎是完美的算法。

运行时间中的对数

对数最常出现的规律概括为以下法则:

如果一个算法用常数时间(O(1))将问题的大小消减为其一部分(通常是1/2),那么该算法就是O(logN)。

另一方面,如果使用常数时间只是把问题减少一个常数(如将问题减少1),那么这种算法就是O(N)。

(假设数据已经提前读入)

对分查找

(1)问题:给定一个整数X和整数A0、A1…、An-1,后者已经预先排序并在内存中,求使得Ai=X的下标i,如果X不在数据中,则返回i=-1.

(2)方法:验证X是否是居中元素(二分法)

(3)时间计算:将问题的大小缩减为原来的1/2。所以运行时间为O(logN)。

欧几里德算法

(1)问题:计算最大公因数的欧几里德算法。两个整数的最大公因(Gcd)是同时整除二者的最大整数。例如Gcd(50,15)=5。

(2)方法:算法通过连续计算余数直到余数是0为止,最后的非零余数就是最大公因数。因此,如果M=1989,N=1590,余数序列是399,393,6,3,0,那么Gcd(1989,1590)=3。

(3)时间计算:

1、运行时间依赖于余数序列长度,看不出余数的值按照常数因子(用常数时间O(1)消减问题,才能计算运行时间是O(logN))递减的必然性。

2、两次迭代以后,余数最多是原始值的一半,所以迭代次数至多是2logN=O(logN)),即为运行时间。由以下定理容易得出。

定理:如果M>N,则M mod N<M/2。

欧几里德算法在平均情况下的性能需要大量篇幅的高度复杂的数学分析,其迭代的平均次数约为(12 ln2 lnN)/pi^2+1.47。

幂运算

计算X^N。如果N是偶数,则,如果N是奇数,则

时间计算:O(logN),因为把问题分半最多需要两次乘法。

检验你的分析

方法1:编程并比较实际观察到的运行时间与通过分析所描述的运行时间是否相匹配。

 

方法2:验证一个程序是否是O(f(N))的另一个常用技巧是对N的某个范围(通常用2的倍数隔开)计算比值T(N)/f(N),其中T(N)是凭经验观察到的运行时间.如果f(N)是运行时间的理想近似,那么所算出的值收敛于一个常数。如果f(N)估计过大,则算出的值收敛于0.如果f(N)估计过低从而程序不是O(f(N))的,那么算出的值发散。

分析结果的准确性

经验指出,有时分析会估计过大,或者需要分析得更细,或者可能是平均运行时间显著小于最坏情形的运行时间而又不能对所得的界再加以改进。平均情形的分析极其复杂,而最坏情形的界尽管有些过分悲观但却是最好的已知解析结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值