1 递归方法的讨论
首先,我们来看一个简单的数学函数:,其中:
从上面的定义中,我们可以很清晰的推论出:,
,
,以及
那么,我们如何使用一个简单的java函数来描述这个公式,并根据这个公式拿到正确的解析结果呢?我们直接上代码:
/**
*
* 功能描述: 描述 f(x)=2f(x-1)+x^2 其中:f(0) = 0;
*
* @param:
* @return:
* @auther: CYL
* @date: 2018/9/13 10:36
*/
public static int f(int x){
if(x == 0) return 0;
else return 2*f(x-1)+x*x;
}
这里我们需要明确的是,java提供的仅仅是对递归思想的一种尝试,不是所有的数学递归函数都可以被有效的使用java代码来实现。上面代码中if(x == 0 ) 处理的是一个基准情况,即如果满足这个条件,就可以直接返回数据,而不需要执行递归函数,正如上面 中若是没有
这个条件,其在数学意义上是没有意义的,没有办法计算出任何的一个函数值,同样,java中递归方法失去了基准情况也是没有任何意义的。
跟踪挂起的函数调用(这些调用已经开始,但是正在等待递归调用来完成)以及他们的变量记录都是由计算机来完成的。然而重要的问题是,递归调用将反复进行,直到基准情况的出现。例如在上面的递归中,我们想获取f(-1)的值,那么势必会调用f(-2)的值,以此类推,我们永远不可能拿到f(-1)的值,甚至在特殊的情况下,甚至会发生更加微妙的事情:
/**
*
* 功能描述: 描述 f(x)=f(x/3+1)+x^2 其中:f(0) = 0;
*
* @param:
* @return:
* @auther: CYL
* @date: 2018/9/13 10:36
*/
public static int bad(int x){
if(x == 0) return 0;
else return bad(x/3+1)+x*x;
}
这里我们想获取bad(1)的结果,但是这个定义其实是给不出任何的结果的,计算机将会反复调用bad(1)以期解出他的值,最后,计算机的内存空间将被消耗殆尽,导致系统崩溃
经过上面的讨论,我们可以得出两个结论:
基准情形:必须总要有一些基本的情形,使得递归方法在不使用递归的情况下可以直接拿到对应的值
不断推进:递归的调用应当总是想着基准情形推进
其中还有其他的两个原则是我们必须考虑到的:
设计法则:假设所有的递归调用都能完成
合成效益法则:的在求解一个问题的同一实例时,切勿在不同的递归调用中做重复性的工作
递归和循环
这里我们需要明白的是在递归调用中,我们调用的是方法的本身,但是我们并没有使用方法本身定义该方法的一个特定的实例,换句通俗的话讲,通过使用f(5)得到f(5)的值才是循环,通过使用f(4)得到f(5)的值不能称之为循环