浅谈递归算法与迭代算法——从Fibbonacci数列说起

意大利数学家列昂纳多·斐波那契(Leonardo Fibonacci)在著作《算盘书》(Liber Abaci)中提到了一个兔子繁殖问题,其题意大致如下:一般而言,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔来。如果所有兔都不死,那么一年以后可以繁殖多少对兔子?

我们拿一对刚出生的小兔来分析:第一个月初小兔子没有繁殖能力,所以是一对;第二个月初始小兔依然没有繁殖能力,还是一对;两个月后,也就是第三个月初,生下一对小兔,总数共有两对;三个月以后,老兔子又生下一对,因为小兔子还没有繁殖能力,所以一共是三对;以此类推。我们把兔子的对数列成表格:

第N个月初

1

2

3

4

5

6

7

8

9

10

11

12

兔子对数

1

1

2

3

5

8

13

21

34

55

89

144

我们将第1个月初,第2个月初,第3个月初,……,第n个月初的所有的兔子对数设为F(1),F(2),F(3),...,F(n)。在第n个月初的F(n)对兔子中,上个月的兔子已经存在了,有F(n-1)对;而这个月新出生的小兔,则是这F(n-1)对中的长成大兔的那些,也就是上上个月存在的那些兔子生出来的,共有F(n-2)对。所以由此我们得到了兔子繁殖的一个公式:

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

           前两个月因为小兔还没有繁殖能力,所以F(1)=F(2)=1                                                       (1.2)

 现在只注意式(1.1)与式(1.2),我们就得到了一个有趣的数列,从第三项开始,它的每一项都等于前面相邻两项之和,人们将这个数列称作斐波那契数列(Fibonacci sequence),由于我们是由此来探讨简单算法,在此关于斐波那契数列的更多内容不再赘述。

下面我们来研究如何用算法编写求斐波那契数列任意项的代码。

 首先我们引入这样几个概念:递归、递推、迭代。(均引自百度百科)

 递推(recursive)是一种用若干步可重复运算来描述复杂问题的方法,是序列计算中的一种常用算法。通常是通过计算机前面的一些项来得出序列中的指定项的值。递推是按照一定的规律来计算序列中的每个项,通常是通过计算前面的一些项来得出序列中的指定项的值。其思想是把一个复杂的庞大的计算过程转化为简单过程的多次重复,该算法利用了计算机速度快和不知疲倦的机器特点。

迭代(iteration)是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。重复执行一系列运算步骤,从前面的量依次求出后面的量的过程。此过程的每一次结果,都是由对前一次所得结果施行相同的运算步骤得到的。例如利用迭代法求某一数学问题的解。对计算机特定程序中需要反复执行的子程序(一组指令),进行一次重复,即重复执行程序中的循环,直到满足某条件为止,亦称为迭代。

递归(recursion)是一种调用自身的编程算法。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。

 这几种概念互有联系与区别,而递推和迭代较难区分,递归较难理解。我们首先明确一下递推和迭代的关系,递推和迭代都是通过不断循环重复运算来不断逼近所求值,两者之间并没有特别明显的区别,可一般递推算法在代码中要设置数组,这样我们可以来查看它的运算过程,以及每一项所求值的内容;而迭代只需要设置若干变量不断向前交替推进即可,不容易查看中间量。两者各有长短,依照需求自行选择。这里主要谈迭代算法与递归算法的使用。

1、迭代算法求斐波那契任意项

            迭代算法的步骤:

            1、 确定迭代变量:确定一个直接或间接地不断由旧值推断新值的变量。

            2、建立迭代关系式:从变量的旧值推断到新值的公式,如f(n) = f(n-1)+n。

            3、设置循环终止条件。

通俗来说,迭代思想就好比走路,两只脚交替向前,最终到达目的地,迭代算法就是运用若干变量,不断交替地运算赋值,来向所求值逼近。我们用代码说明这一点。

#include <stdio.h>
int main()
{
	int n,f1,f2,f3;
	int i;
	while (scanf("%d",&n),n!=-1)//输入-1来终止程序
    {
        f1=1;
        f2=1;
        f3=2;  //这里需要给变量赋一个初值来准备循环运算
        for (i=2;i<n;i++)
        {
            f1=f2;
            f2=f3;
            f3=f2+f1;//每个变量都不断赋得新值,或运算或由前面的变量提供
        }
        printf ("%d\n",f2);
    }
	return 0;
}

2、递归算法求斐波那契数列任意项

 递归算法的步骤: 
            1、确定递归公式 。
            2、确定递归结束条件。

递归算法,主要思路就是从终点起不断调用函数本身来回溯初始位置,再向上运算到达终点,有一个往返的过程。通常需要编写被调函数来实现需求。代码清晰,可读性较强。

#include <stdio.h>
int fib(int n)
{
    if (n==1||n==2)
        return n=1;//前两项是起始位置,所以我们单独把它写出来
    return fib(n-1)+fib(n-2);//这里看出,递归算法有一个直观的公式可以参考
}
int main()
{
	int n;
	int i;
	while (scanf("%d",&n),n!=-1)//输入-1来终止程序
        printf ("%d\n",n=fib(n));
	return 0;
}

被调函数中的return fib(n-1)+fib(n-2)中的fib(n-1)和fib(n-2),这两项都需要不断调用fib函数来运算,一直到n=1或n=2时停止,返回1,然后每一步再进行运算,回到n的输入值。
 

 

一个问题是否可以用迭代算法或者递归算法解决,可以这样简单地来进行思考:是否可以由简单情况来推导至最终我们看到的问题?是否可以用重复的运算来满足需求?是否存在一个地方可以终止循环运算?

以上就是迭代算法与递归算法的简单编写,值得注意的是,迭代算法的时间复杂度要比递归算法小很多,这不难看出,因为递归是一个往返的过程,如果数据较大,这个差距就会非常明显,这也是为什么在许多ACM题目里提交递归算法编写的代码会出现时间超限的错误,在此时不妨换个思路用迭代算法重新编写。一般来说,递归算法可以与迭代算法互相转换,可需要注意:递归算法需要终止条件,而如果回溯过深的话就会导致堆栈溢出。

 

 

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值