如果要用Java实现算法,一定慎用递归
2013-01-25 23:10
225 查看
现象 :
递归是我们很经典的一种算法实现,可以很好的描述一个算法的原理!对于算法的描述、表现和代码结构理解上,递归都是不错的选择!
但是本文想说的是java实现一个递归算法的时候尽量不要用递归实现,而是转换成的非递归实现。
最近在实现一个比较复杂算法的时候,尝试了一下,非递归实现相比递归实现速度上能提升1/3。
以下面一个简单的例子来说:(注:为了描述简单,所以这里只用一个简单的例子)
输入参数:N
输出结果: log1+log2+log3+....+logN
两种实现代码如下:
Java代码
得到运行结果如下:
可以看出递归的运行时间是非递归运行时间将近2倍。
(注:以上代码还是在-Xss200m的参数下运行的,如果栈空间不足,直接不能运行)
原因简单分析:
上图是java线程栈的结构。java将为每个线程维护一个堆栈,堆栈里将为每个方法保存一个栈帧,栈帧代表了一个方法的运行状态。 也就是我们常说的方法栈。最后一个为当前运行的栈帧。
那么每一次方法调用会涉及:
1.为新调用方法的生成一个栈帧
2.保存当前方法的栈帧状态
3.栈帧上下文切换,切换到最新的方法栈帧。
递归实现将导致在栈内存的消耗(往往需要调整Xss参数)和因为创建栈帧和切换的性能开销,最终大大的影响效率!
所以,如果你想提升你的算法效率,不要使用递归实现是一个基础原则!
另外,递归是我们用来理解算法的一个方法,当用代码来实现的时候基本都可以转换成非递归的代码实现!
递归是我们很经典的一种算法实现,可以很好的描述一个算法的原理!对于算法的描述、表现和代码结构理解上,递归都是不错的选择!
但是本文想说的是java实现一个递归算法的时候尽量不要用递归实现,而是转换成的非递归实现。
最近在实现一个比较复杂算法的时候,尝试了一下,非递归实现相比递归实现速度上能提升1/3。
以下面一个简单的例子来说:(注:为了描述简单,所以这里只用一个简单的例子)
输入参数:N
输出结果: log1+log2+log3+....+logN
两种实现代码如下:
Java代码
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)); } }
得到运行结果如下:
recursive result:7.212475098340103E7 recursive time used:539457109 non-recursive result:7.212475098340103E7 non-recursive time used:282479757
可以看出递归的运行时间是非递归运行时间将近2倍。
(注:以上代码还是在-Xss200m的参数下运行的,如果栈空间不足,直接不能运行)
原因简单分析:
上图是java线程栈的结构。java将为每个线程维护一个堆栈,堆栈里将为每个方法保存一个栈帧,栈帧代表了一个方法的运行状态。 也就是我们常说的方法栈。最后一个为当前运行的栈帧。
那么每一次方法调用会涉及:
1.为新调用方法的生成一个栈帧
2.保存当前方法的栈帧状态
3.栈帧上下文切换,切换到最新的方法栈帧。
递归实现将导致在栈内存的消耗(往往需要调整Xss参数)和因为创建栈帧和切换的性能开销,最终大大的影响效率!
所以,如果你想提升你的算法效率,不要使用递归实现是一个基础原则!
另外,递归是我们用来理解算法的一个方法,当用代码来实现的时候基本都可以转换成非递归的代码实现!
相关文章推荐
- [算法]Java 实现 简单MyNode类型 无序链表 递归 添加 删除 遍历
- 8皇后以及N皇后算法探究,回溯算法的JAVA实现,非递归,循环控制及其优化
- (数据结构与算法分析 一)------快速求幂算法,Java递归实现
- Java归并算法递归实现
- 算法:二叉树的先序遍历、中序遍历、后序遍历(递归及非递归方式)的java代码实现
- 背包算法递归实现,递归转动态规划的一般方法java实现
- 8皇后以及N皇后算法探究,回溯算法的JAVA实现,非递归,数据结构“栈”实现
- 算法(第四版)学习笔记之二分查找的递归与非递归java实现
- 【Fiay】【Java】汉诺塔算法 递归实现
- 班主任来啦之观察者模式,事件委托等Java实现---如果你还不懂,看完此文,就一定会懂
- 8皇后以及N皇后算法探究,回溯算法的JAVA实现,递归方案
- [算法入门]快速排序非递归方法(Java实现),大家一起来找茬啊~
- Java基于循环递归回溯实现八皇后问题算法示例
- 【数据结构与算法】汉诺塔算法——java递归实现
- 【算法数据结构Java实现】递归的简单剖析及时间复杂度计算
- 算法:二叉树的先(根)序遍历、中(根)序遍历、后(根)序遍历(递归及压栈出栈实现的非递归方式)的java代码实现
- [Java算法分析与设计]二叉树非递归实现遍历
- java实现二叉树的三种遍历算法(递归)
- 笔试面试算法经典--二叉树的镜像-递归与非递归实现(Java)
- 算法学习 八皇后问题的递归实现 java版 回溯思想