锁定老帖子 主题:如果要用java实现算法,一定慎用递归
精华帖 (0) :: 良好帖 (0) :: 新手帖 (9) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-04-06
最后修改:2011-04-07
现象 : 递归是我们很经典的一种算法实现,可以很好的描述一个算法的原理!对于算法的描述、表现和代码结构理解上,递归都是不错的选择! 但是本文想说的是java实现一个递归算法的时候尽量不要用递归实现,而是转换成的非递归实现。 最近在实现一个比较复杂算法的时候,尝试了一下,非递归实现相比递归实现速度上能提升1/3。 以下面一个简单的例子来说: (注:为了描述简单,所以这里只用一个简单的例子。这个例子可以用更简单的数学公式来实现,所以请大家不要过分在意。 重点是想说明递归可能带来的一些问题) 输入参数:N 输出结果: log1+log2+log3+....+logN 两种实现代码如下:
package test; public class RecursiveTest { /** * 递归实现 * * @param n * @return */ public static double recursive(long n) { if (n == 1) { return Math.log(1); } else { return Math.log(n) + recursive(n - 1); } } /** * 非递归实现 * * @param n * @return */ public static double directly(long n) { double result = 0; for (int i = 1; i <= n; i++) { result += Math.log(i); } return result; } public static void main(String[] args) { int i = 5000000; long test = System.nanoTime(); long start1 = System.nanoTime(); double r1 = recursive(i); long end1 = System.nanoTime(); long start2 = System.nanoTime(); double r2 = directly(i); long end2 = System.nanoTime(); System.out.println("recursive result:" + r1); System.out.println("recursive time used:" + (end1 - start1)); System.out.println("non-recursive result:" + r2); System.out.println("non-recursive time used:" + (end2 - start2)); } } 得到运行结果如下:
可以看出递归的运行时间是非递归运行时间将近2倍。 (注:以上代码还是在-Xss200m的参数下运行的,如果栈空间不足,直接不能运行)
原因简单分析:
上图是java线程栈的结构。java将为每个线程维护一个堆栈,堆栈里将为每个方法保存一个栈帧,栈帧代表了一个方法的运行状态。 也就是我们常说的方法栈。最后一个为当前运行的栈帧。 那么每一次方法调用会涉及: 1.为新调用方法的生成一个栈帧 2.保存当前方法的栈帧状态 3.栈帧上下文切换,切换到最新的方法栈帧。
递归实现将导致在栈内存的消耗(往往需要调整Xss参数)和因为创建栈帧和切换的性能开销,最终大大的影响效率!
所以,如果你想提升你的算法效率,不要使用递归实现是一个基础原则! 另外,递归是我们用来理解算法的一个方法,当用代码来实现的时候基本都可以转换成非递归的代码实现!
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-04-06
循环与递归,一般可以用循环解决的当然首选循环。
但是递归解决问题简单明了,有时候递归更快,例如解决汉诺塔问题不用递归的话,恐怕更慢。 |
|
返回顶楼 | |
发表时间:2011-04-06
递归一般用来
1、复杂度不高,N不大 2、问题复杂,易理解,简单明了 具体问题具体分析,比如,递归通过限制条件降低复杂度, 增加步长,简化问题或模型,再或者化成非递归形式。 比如lz的问题,N很大的时候,直接用阶乘的stirling表达式。 |
|
返回顶楼 | |
发表时间:2011-04-07
kimmking 写道 递归一般用来
1、复杂度不高,N不大 2、问题复杂,易理解,简单明了 具体问题具体分析,比如,递归通过限制条件降低复杂度, 增加步长,简化问题或模型,再或者化成非递归形式。 比如lz的问题,N很大的时候,直接用阶乘的stirling表达式。 是的 这里的例子只是为了说明一下递归存在的问题 所以举了一个简单的例子! 我真正实现的算法是比较复杂的,一开始是用递归,后面改成非递归实现,有很大提升! |
|
返回顶楼 | |
发表时间:2011-04-07
学习了 递归的开销问题
|
|
返回顶楼 | |
发表时间:2011-04-07
如果不是重要的模块,用递归可以简洁很多。。用不用递归要多方面考虑,性能和代码复杂度之间都要有所权衡。。
|
|
返回顶楼 | |
发表时间:2011-04-07
这个东西,用数学方式比用程序一步一步的傻算有效得多
|
|
返回顶楼 | |
发表时间:2011-04-07
除非疯子才一个一个算logx相加 .......
向楼上所说递归是用来简单化来表达数据处理的思想 要是不用递归试试计算 f(n)=f(n-1)+f(n-2)+f(n-3)+f(n-4)+f(n-5) 不管是用非递归或推数学公式(上面公式已经要计算一元五次方程的解了),会非常复杂 |
|
返回顶楼 | |
发表时间:2011-04-07
而且想说,你的代码程序,log精度早丢失了
|
|
返回顶楼 | |
发表时间:2011-04-07
cttnbcj 写道 除非疯子才一个一个算logx相加 .......
向楼上所说递归是用来简单化来表达数据处理的思想 要是不用递归试试计算 f(n)=f(n-1)+f(n-2)+f(n-3)+f(n-4)+f(n-5) 不管是用非递归或推数学公式(上面公式已经要计算一元五次方程的解了),会非常复杂 五次方程没有根式解, 手工计算5个根有点累。 计算机计算起来比较容易。 |
|
返回顶楼 | |