`
singleant
  • 浏览: 379126 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

如果要用java实现算法,一定慎用递归

阅读更多

 

现象

递归是我们很经典的一种算法实现,可以很好的描述一个算法的原理!对于算法的描述、表现和代码结构理解上,递归都是不错的选择!

但是本文想说的是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));
	}
}
 

得到运行结果如下:


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参数)和因为创建栈帧和切换的性能开销,最终大大的影响效率!

 

所以,如果你想提升你的算法效率,不要使用递归实现是一个基础原则!

另外,递归是我们用来理解算法的一个方法,当用代码来实现的时候基本都可以转换成非递归的代码实现!

 

  • 大小: 79.2 KB
分享到:
评论
32 楼 clarkhill 2014-11-13  
汉诺塔其实有数学公式能够解决。
31 楼 kingsword 2011-09-04  
稍微给楼主纠个字面上的小不妥“java将为每个线程维护一个堆栈,堆栈里将为每个方法保存一个栈帧,”那个“堆栈”说成是Java栈好些,说成是堆栈,容易给初学者造成迷惑。
30 楼 hdenghui 2011-04-08  
学习,学习…
29 楼 tangqs 2011-04-08  
不过对于递归很深的程序由于很容易引发 栈溢出异常,所以在这样的情况下,用非递归算法更合适一些。
28 楼 tangqs 2011-04-08  
在Java中,JVM对递归调用有优化的,所以在很多情况之下递归调用的效率会比非递归高,lz的递归程序的例子并没有普遍意义,因为这个非递归程序没有用到栈结构,如果你真的要做例子,你可以在试试快速排序的递归和非递归算法。
27 楼 seanla 2011-04-08  
kimmking 写道
cttnbcj 写道
除非疯子才一个一个算logx相加 .......
向楼上所说递归是用来简单化来表达数据处理的思想

要是不用递归试试计算 f(n)=f(n-1)+f(n-2)+f(n-3)+f(n-4)+f(n-5)
不管是用非递归或推数学公式(上面公式已经要计算一元五次方程的解了),会非常复杂

五次方程没有根式解,
手工计算5个根有点累。
计算机计算起来比较容易。

可以考虑用演化计算,选择一个比较好的算子,很快就能算出最优解
26 楼 optimism_best 2011-04-07  
好贴,递归的用法还不是很清楚,在N很大的情况下递归的性能确实不乐观
25 楼 wolf521hf 2011-04-07  
学习了    
24 楼 sdh5724 2011-04-07  
用递归的时候, 得清楚自己是在干么, 否则就不要用。 就跟用正则一样得道理。  很多东西没有完美。用的时候都得想清楚。
23 楼 beykery 2011-04-07  
也要看什么情况啊楼主,有些算法递归实现确实很清晰,还有些算法把递归写成非递归形式还非常困难。比如alpha beta剪支我就不知道怎么写成非递归。
22 楼 gundumw100 2011-04-07  
个人感觉递归用于for循环次数不定的情况.
for
  for
    for
      ......
21 楼 realvalkyrie 2011-04-07  
用迭代来表示,即满足递归的明了,性能也相对来说可以接受:
结果以参数的形式传递,这样可以省去递归由于要保存栈信息而带来的开销。
20 楼 jackra 2011-04-07  
递归本身针对可扩展性多状况结构的数据有很强大处理能力.
如果要做一些可扩展的组件,递归是不可避免的.
不会递归可耻;滥用递归也可耻;不会正确的使用递归同样可耻。
19 楼 kamhung 2011-04-07  
不是递归本身慢, 是java调用方法慢, 例子1跟例子2的区别在于例子2少调用了方法, 这两个例子都运行几次就会发现两个耗时会越来越接近, 因为java对频繁调用的方法进行优化~
18 楼 Crusader 2011-04-07  
递归是用来简化求解难度的
但如果迭代次数过多的话,会影响性能
17 楼 math_xl 2011-04-07  
递归 代码比较整洁

空间消耗代价
16 楼 schweigen 2011-04-07  
在Sun JDK 下跑,第一次确实差距挺大,再运行第二次的结果(也许可能要多运行几次):

recursive result:7.212475098340103E7
recursive time used:312802755
non-recursive result:7.212475098340103E7
non-recursive time used:312842609

JDK 对尾递归还是会自己做优化的
15 楼 freish 2011-04-07  
每每看到递归都后怕,StackOverflowError是个心理阴影
14 楼 singleant 2011-04-07  
cttnbcj 写道
除非疯子才一个一个算logx相加 .......
向楼上所说递归是用来简单化来表达数据处理的思想

要是不用递归试试计算 f(n)=f(n-1)+f(n-2)+f(n-3)+f(n-4)+f(n-5)
不管是用非递归或推数学公式(上面公式已经要计算一元五次方程的解了),会非常复杂


你根本就不理解本帖子要说明什么! 只是想说明递归的开销!
例子不是最重要的,"除非疯子才一个一个算logx相加 ....... "这个大家都懂得,不要过分去在意这个。
13 楼 kimmking 2011-04-07  
cttnbcj 写道
kimmking 写道
cttnbcj 写道
除非疯子才一个一个算logx相加 .......
向楼上所说递归是用来简单化来表达数据处理的思想

要是不用递归试试计算 f(n)=f(n-1)+f(n-2)+f(n-3)+f(n-4)+f(n-5)
不管是用非递归或推数学公式(上面公式已经要计算一元五次方程的解了),会非常复杂

五次方程没有根式解
手工计算5个根有点累。
计算机计算起来比较容易。

你确定无解?只是无代数根式解
五次方程符合Galois群理论,就可以有解。。。。(x-a)(x-b)(x-c)(x-d)(x-e)=0 a,b,c,d,e都不相等,这个五次方,你说有解吗?

相关推荐

    部门绩效考核评价表excel.xls

    部门绩效考核评价表excel

    全面的公司行政费用统计表.xls

    全面的公司行政费用统计表

    视觉跟踪算法综述.pdf

    视觉跟踪算法综述.pdf

    CMD 命令行高级教程精选合编

    CMD 命令行高级教程精选合编

    apr-devel-1.4.8-7.el7.x64-86.rpm.tar.gz

    1、文件内容:apr-devel-1.4.8-7.el7.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/apr-devel-1.4.8-7.el7.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、安装指导:私信博主,全程指导安装

    10-4-生产主管绩效考核表(自动计算、等级评价).xlsx

    10-4-生产主管绩效考核表(自动计算、等级评价)

    深度学习python基础(第三节) 函数、列表

    深度学习python基础(第三节) 函数、列表

    岗位绩效考核评定表excel表格模板.xlsx

    岗位绩效考核评定表excel表格模板

    成品库仓管员绩效考核表.xls

    成品库仓管员绩效考核表

    环卫业务 基础知识培训(小步创想)PPT(133页).pptx

    一、智慧环卫管理平台的建设背景与目标 智慧环卫管理平台的建设源于对环卫管理全面升级的需求。当前,城管局已拥有139辆配备车载GPS系统、摄像头和油耗传感器的环卫车辆,但环卫人员尚未配备智能移动终端,公厕也缺乏信息化系统和智能终端设备。为了提升环卫作业效率、实现精细化管理并节省开支,智慧环卫管理平台应运而生。该平台旨在通过信息化技术和软硬件设备,如车载智能终端和环卫手机App,实时了解环卫人员、车辆的工作状态、信息和历史记录,使环卫作业管理透明化、精细化。同时,平台还期望通过数据模型搭建和数据研读,实现更合理的环卫动态资源配置,为环卫工作的科学、健康、持续发展提供决策支持。 二、智慧环卫管理平台的建设内容与功能 智慧环卫管理平台的建设内容包括运行机制体制建设、业务流程设计、智慧公厕系统建设、网络建设、主机和储存平台需求、平台运维管理体系、硬件标准规范体系以及考核评价体系等多个方面。其中,智慧公厕系统建设尤为关键,它能实时监控公厕运行状态,保障公厕的清洁和正常运行。平台建设还充分利用了现有的电子政务网络资源,并考虑了有线和无线网络的需求。在功能上,平台通过普查、整合等手段全面收集环卫车辆、企业、人员、设施、设备等数据,建立智慧环卫基础数据库。利用智能传感、卫星定位等技术实现环卫作业的在线监管和远程监控,实现对道路、公共场所等的作业状况和卫生状况的全面监管。此外,平台还建立了环卫作业网格化管理责任机制,实现从作业过程到结果的全面监管,科学评价区域、部门、单位和人员的作业效果。 三、智慧环卫管理平台的效益与风险规避 智慧环卫管理平台的建设将带来显著的环境、经济和管理效益。环境方面,它将有力推进环境卫生监管服务工作,改善环境卫生状况,为人民群众创造更加清洁、卫生的工作和生活环境。经济方面,通过智慧化监管,大大降低了传统管理手段的成本,提高了监管的准确性和效率。管理方面,平台能够追踪溯源市民反映的问题,如公厕异味、渣土车辆抛洒等,并找到相应的责任单位进行处置,防止类似事件再次发生。同时,平台还拥有强大的预警机制功能,能够在很多环卫问题尚未出现前进行处置。然而,平台建设也面临一定的风险,如部门协调、配合问题,建设单位选择风险以及不可预测的自然灾害等。为了规避这些风险,需要加强领导、统一思想,选择优秀的系统集成商承接项目建设,并做好计算机和应用系统的培训工作。同时,也要注意标准制定工作和相关法律法规的制定工作,以保证系统建设完成后能够真正为环卫管理工作带来便利。

    基于平衡计分卡绩效考核表(管理高层)模板.xls

    基于平衡计分卡绩效考核表(管理高层)模板

    网站运营各部门绩效考核表.xls

    网站运营各部门绩效考核表

    XX公司行政部绩效考核指标.xls

    XX公司行政部绩效考核指标

    基于齿向修形的抛物线锥齿轮仿真分析.pdf

    基于齿向修形的抛物线锥齿轮仿真分析.pdf

    三相半桥逆变器低电压穿越控制策略设计:两级式光伏并网系统电路原理与容量优化报告,两级式光伏并网系统及其低电压穿越控制策略设计,容量30kW 三相半桥逆变器,boost电路作前级 带低电压穿越,有一

    三相半桥逆变器低电压穿越控制策略设计:两级式光伏并网系统电路原理与容量优化报告,两级式光伏并网系统及其低电压穿越控制策略设计,容量30kW。 三相半桥逆变器,boost电路作前级。 带低电压穿越,有一万七千字的报告,没有水文字。 报告内容,电路原理,pi参数设计,bode和根轨迹分析,波形良好 ,关键词:两级式光伏并网系统;低电压穿越控制策略;30kW容量;三相半桥逆变器;boost电路;前级设计;低电压穿越功能;报告内容;电路原理;PI参数设计;Bode和根轨迹分析;波形良好。,基于30kW容量两级式光伏并网系统的控制策略设计:低电压穿越及高效逆变技术研究

    毕业设计文本预测项目python源码+托尔斯泰《战争与和平》文本分析数据集-最新出炉.zip

    毕业设计文本预测项目python源码+托尔斯泰《战争与和平》文本分析数据集-最新出炉 关于数据集 背景: 该数据集包含列夫·托尔斯泰的《战争与和平》的全文,这是一部于 1869 年出版的开创性文学作品。作为公共领域文本,它为对文学分析、自然语言处理和历史研究感兴趣的研究人员和爱好者提供了丰富的资源。这部小说以俄国拿破仑战争为背景,探讨了战争、和平和人类状况的主题。 内容: 数据集由一个纯文本文件组成,其中包含《战争与和平》的完整叙述。文本已进行预处理,以方便分析和建模,使其适用于各种应用,包括文本挖掘、情感分析和机器学习项目。该文件可通过以下链接访问:战争与和平文本数据集。

    18 -广告部经理绩效考核表1.xlsx

    18 -广告部经理绩效考核表1

    永磁同步电机电流内环PR控制Simulink仿真模型:转速电流双闭环矢量控制,波形完美带原理说明与文献参考,永磁同步电机电流内环PR控制Matlab simulink仿真模型,参数已设置好,可直接运行

    永磁同步电机电流内环PR控制Simulink仿真模型:转速电流双闭环矢量控制,波形完美带原理说明与文献参考,永磁同步电机电流内环PR控制Matlab simulink仿真模型,参数已设置好,可直接运行。 属于PMSM转速电流双闭环矢量控制系统模型。 电流内环采用PR控制器,不需要旋转坐标变,在静止坐标下进行矢量控制,转速外环采用PI控制器。 波形完美,包含原理说明文档和参考文献。 ,关键词:永磁同步电机;电流内环PR控制;Matlab simulink仿真模型;PMSM转速电流双闭环矢量控制系统;PR控制器;PI控制器;波形完美;原理说明文档;参考文献。,"基于PR控制的永磁同步电机电流内环仿真模型:静止坐标矢量控制与波形解析"

    基于主从博弈理论的共享储能与综合能源微网优化运行策略研究:Stackelberg均衡下的优化调度与运行框架,基于主从博弈理论的共享储能与综合能源微网优化运行研究 关键词:主从博弈 共享储能 综合能源微

    基于主从博弈理论的共享储能与综合能源微网优化运行策略研究:Stackelberg均衡下的优化调度与运行框架,基于主从博弈理论的共享储能与综合能源微网优化运行研究 关键词:主从博弈 共享储能 综合能源微网 优化调度 参考文档:《基于主从博弈理论的共享储能与综合能源微网优化运行研究》完全复现 仿真平台:MATLAB yalmip+cplex 主要内容:代码主要做的是基于主从博弈理论的共享储能与综合能源微网优化运行研究,首先介绍了系统运行框架,分析了系统内各利益体的功能。 其次,分别针对微网运营商、共享储能服务商以及用户聚合商建立优化运行模型。 进一步,分析了微网运营商与用户聚合商间的博弈关系,提出共享储能背景下微网运营商与用户聚合商间的 Stackelberg 博弈模型,并证明Stackelberg 均衡解的存在性与唯一性。 最后,在 MATLAB平台上进行算例仿真,通过 Yalmip 工具与 CPLEX 求解器进行建模与求解,利用启发式算法与求解器相结合的方法优化微网运营商与用户聚合商的策略。 结果表明,本文所提模型所提模型不仅能有效权衡微网运营商与用户聚合商的利益,也实现了用户聚合商

Global site tag (gtag.js) - Google Analytics