逻辑成本
今天在调优小伙伴代码的时候
偶然发现一个方法,逻辑上差不多是这样:
public static long demo (int i){
if ( i <= 1) {
return 1;
}else{
return i * demo( i - 1);
}
}
其实正常来看没什么问题,编译执行都没问题,而且用了递归算法,基准情况值为1,
但其实这个递归用的并不好,实际上就是一个被包装的for循环,时间为O(N)
可修改成:
/**
* @parm n为上面递归方法参数i
*/
long l = 0;
for (int i = 0; i <= n; i++) {
if (i <= 1) {
l = 1;
} else {
l = i * l;
}
}
此递归被正常使用时,将其转成一个循环结构是相当困难的,分析将涉及求解一个递推关系,代码逻辑成本将提高。
时间成本
然后由此延展:
public static long demo (int i){
if ( i <= 1) {
return 1;
}else{
return demo( i - 1) + demo( i - 2);
}
}
乍看此程序很高大上,可是可以测试一下,当i值为40左右时运行,这个程序的效率低的吓人。
简单分析一下,
令T(i)为调用函数demo(i)的运行时间。
如果i=0或者i=1,运行第一个ture逻辑返回常数1.
若i>2,则执行该方法的时间时第一行判断加上判断false后的运算——俩次方法调用和一次加法。
由于方法调用不是简单的运算,因此必须用方法内部外展分析,按照T的定义第一个调用它需要T(i-1)个时间单元。第二个调用要T(i-2)个时间单元,所以总时间需要T(i-1)+T(i-2)+2,2时值得第一行常数判断和false逻辑内加法运算,
所以: T(i)=T(i-1)+T(i-2)+2
因demo(i)=demo( i - 1) + demo( i - 2),由归纳法证明t(i)>=demo(i),归纳法定理,所以类似计算可以证明
(当i>4时),从而看出程序时间以指数的速度增长。
所以如果更换成一个简单数组加上for循环,运行时间能显著降低。