java中的递归

131 阅读5分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

一、递归在数学函数中的意义

有的时候,数学函数以不太标准的形式定义。例如,我们可以在非负数集上定义一个函数f,它满足f(0)=0且f(x)=2f(x-1)+x*x。 丛这个定义我们可以看到 f(1)=1, f(2)=6, f(3)=21, 以及 f(4)=58 当一个函数用它自己来定义时就称之为是递归的。 在java中允许函数是递归的。

但是值得记住的是,java仅仅是提供遵循递归思想的一种尝试。不是所有的数学递归函数都能被有效地(正确地)由java递归模拟来实现。

上面所说的递归函数f,只需要用几行简短的代码就能表示出来。

例如: 在这里插入图片描述 第10、11行处理基准情况,即就是此时的函数可以直接通过参数值的传递而算出,而不求助递归。

正如:f(x)=2f(x-1)+x*x若没有f(0)=0这个事实在数学上没有意义一样,java的递归方法若无基准情况也是毫无意义的。第13行执行的是递归调用

关于递归有几个重要的概念,不应该被混淆 1、递归是否就是遵循循环推理呢?? 答案是:虽然我们定义一个方法用的是这个方法本身,但是我们并没有用方法的本身去定义一个方法的特定的实例。懂得人都懂。 例如: 在面向对象编程中,我定义javaBean实体类,我只是提供一个模版,并没有具体提供一个对象,我可以通过new关键字来创建一个新的对象

而在递归中特定的实例,就是一个特定的对象。

二、对于数值计算,通常使用递归不是一个好主意

那么递归调用是怎样进行执行运算的呢?

加入我们传递的参数是6 那么f(x)=2f(6-1)+ 66;

这个时候就需要我们知道f(5)=?

那么开始进行替换

那么就需要我们继续去找 f(4).........f(3)..........f(2).一直找到f(0) 然后通过f(0)=0,确定f(1)=1, 通过f(1)=1,确定f(2)=6, 。。。。。。。。。。。 。。。。。。。。 最终得出f(6)=318 在这里插入图片描述

而实际上,递归调用将会反复进行知道出现基准情况, 例如当计算f(-1),那么会导致调用f(-2),f(-3)等等。由于这些情况不可能出现基准情况,因此程序也算不出答案,偶尔还会发生更微妙的错误。 以下是当我们求f(-1)发生的错误 在这里插入图片描述 当调用次数或者内存消耗达到一定程度,虚拟机会自动帮我们停止,并抛出异常。

三、错误示例

下面的例子是一种微妙的错误: 在这里插入图片描述 错误在第13行上,因为把bad(1)定义为bad(1),。显然,实际上bad(1),究竟是多少,这个定义给不出任何线索,因此计算机会反复进行调用,以期望能解除他的值,最后计算机系统内存将占满,一般的情况下,我们会说该方法 在特殊的情况下是无效的,而在其他情形是正确的,但此处这么说则不正确,因为bad(2)调用bad(1),但是bad(1)解不出值来,因此bad2也解不出值来,bad3、4、5等都需要调用bad2,所以因为bad1解不出值来,其他的都解不出值来,除了0之外,这个程序对任何非负值都是无效的。对于递归程序,不存在像特殊情形的这样情况下。 上面的讨论导致递归的前2个基本法则:

1、基准情形。

必须总要有某些特殊基准情形,他们不用递归就能求解

2、不断推进。

对于那些要求递归求解的情形,递归调用必须总能够朝着一个基准情形推进。

现在给出我们为什么会有第三个设计法则

假设现在要打印输出一个n正整数 例如0.......9........11.......一直到正无向大 那么引入一个一个函数,就是我们的函数一次只能处理单个数字,并把它输出到屏幕终端上,当然0-9是最好输出的,直接传递参数即可 那么假如是11呢?,这是个2位数,假如是111呢,或者是1289这类数呢? ,值得我们注意的是,我们即使输入的数1289这样的数,其实我们不是通过一次输出而显示成功的,那么当我们要输出9的时候,那么9与1289又有什么关系呢,显而易见,是1289%10=9,那么128与1289又有什么关系呢---->是1289/10=128,那么由此可知,当我们执行1289/10得出128这个数,那么怎样得出12这个数,就是128/10=12, 1就是12/10=1,由此我们的循环定义成功了,因为我们找到了第一个要输出的数,那么第一个要输出的数是1-9 所以通过java编程实现过程就是如下操作: public static void printOut(int n){ if(n>=10) printOut(n/10); printDigit(n%10); }

3、设计法则。

假设所有递归都能够运行

4、合成效益法则。

在求解一个问题的一个实例时,切勿在不同的递归调用中重复性的工作。

使用递归计算例如斐波那契这类函数的值的想法不是一个好的注意,其道理正式根据第四条法则。

有了这些原理和法则,设计一个递归总算容易了许多。