关于递归的一些思考

说到递归,我们张嘴就能说出来是什么?自己调用自己。官方点说就是一个函数用它自己来定义时就是递归。
有时候很多的数学问题或者生活中的问题都可以使用计算机程序来解决,把这些问题统计起来,找出他们之间的规律,得出一个计算公式,用程序来计算这个公式得出结果。梦想总是美好的,有时候我们得出的公式有些是以不太标准的形式定义的。

例如斐波那契数列,通过分析我们得到一个公式,它满足:

                                F(0)=0  
                                F(1)=1
                                F(2)=1

                        F(n)=F(n-1)+F(n-2)(n>=2)

在上面的公式定义中我们发现F(0)=0,F(1)=1,F(2)=1
利用递归我们可以很方便的得到解决这个问题的方法,程序如下:

public int getFib(int n) {
        if (n < 0) {
            return -1;
        } else if (n == 0) {
            return 0;
        } else if (n == 1 || n == 2) {
            return 1;
        } else {
            return getFib(n - 1) + getFib(n - 2);
        }
    }

上面的程序中两个else if用于处理基准情况,何为基准情况?就是函数的值不需要递归计算直接可以得出的结果。一个递归函数必须有基准情况(不需要递归计算就可以得到的结果),没有基准情况的递归方法没有意义。
试着想一想:我们现在要利用上面的程序计算出F(3)的结果是多少?我们发现如果要算F(3)就要知道F(2)和F(1)的值,我们发现F(2)和F(1)的值已经知道了,那么F(3)的结果很容易得到。我们先忘记上面的情况,假如现在我们要计算F(5),根据公式计算F(5)就要知道F(4)和F(3),但是F(4)和F(3)我们不知道,但是可以根据公式算出来,F(4)=F(3)加上F(2),F(3)=F(2)加上F(1),综上所述以后的每一个结果都是根据我们已知的结果算出来的
在上面的程序中两个else if给出了基准所以我们后面的递归计算才可以得到。
上面的推倒结果的过程可以发现递归就是一个循环推理的过程。
还是这个基准的问题,求结果当我们想要求F(1)的时候,如果没有基准,求F(1)就要知道F(0)和F(-1),然后F(0)又要依赖F(-1)和F(-2),这样一直向下计算,永远不能算出结果,显然这是一个错误的程序,这样的结果就是计算机的资源全部都在计算这些没有意义的计算,包括跟踪挂起的函数调用以及他们的变量记录工作都要计算机来完成。所以我们在方法的最开始规定了参数不能小于0。

前面的论述基本上讨论了递归的两个基本准则:
* 基准准则:就像一个开口,不用递归就可以得到的结果
* 不断推进:需要递归求的计算,递归的方向总是朝着基准的方向推进

书上有一个很好的例子助于理解,遇到一个不认识的词语我们要查字典,我们根据下面的解释理解这个词语的意思,但是这段解释中我们又遇到了不认识的词语,我们又要接着查,就这样一直查,直到我们找到了一处我们理解的词语(就是上面说的基准)之前所有的也就理解了。这个查询过程也就结束了。

在设计递归函数的时候我们假设所有的递归都能运行。当递归程序运行起来想要追踪具体的调用关系是很困难的。
记住要有基准,每次递归朝着基准前进


这篇文章根据《数据结构与算法分析》写出,有书上的,也有我的理解,初读这本书感觉真的不一样,字多,书上好多的知识解释的很详细,建议认真阅读!做笔记!我从前对递归的理解就是一句话,总结了之后原来递归的知识可以有这么多。

posted @ 2018-03-17 18:31  In_new  阅读(168)  评论(0编辑  收藏  举报