函数(递归,迭代实现斐波那契数列)

上篇文章介绍了一下函数的基本内容,这次来讲讲函数的编程技巧--递归,迭代。并运用这两个技巧实现的斐波那契数列。

递 归

递归是一个过程或函数在其定义或说明中直接或间接调用自身的一种方法,把一个复杂的问题层层转化为与原问题相似的小问题求解。

特点是只需要少量的程序就可以描述出解题过程中需要的重复计算,大大减少了计算量。(大事化小)

下面讲一个小例子具体介绍一下递归,然后再实现斐波那契数列。

练习:接收一个无符号的整型,按顺序输出它的每一位。例:输入1234,打印1 2 3 4。

写这个程序之前,我们先思考一下该如何才能实现这个功能。

在用户输入整数,这里举例输入1234,如何分解为一个个的数字,首先我想到的就是除10,由于int 只接收整形,所以每除一个10,就可以少一位。这样就可以实现分解为一个个数据了。那么问题又来了,我除三个10可以获得1,除两个10的时候获得的是12,这时候要打印出去的话就是12了,如何打印2出来呢,这里我想到的是用求模,跟10求模。为什么选择的是10,不是1,不是100,因为这里要求的是打印一位数,求10才能实现这个功能。第一个1跟10求模还是1,12跟10求模为2,123跟10求模是3,可以看出完美实现了题目的要求。现在就要想想如何实现这个过程了。

可以看到这个解题的过程很符合我们递归的特点,大事化小。那我们就用递归来实现一下。

可以看到完美符合题目要求,再仔细看下代码,发现我们的Print函数中又包含了Print函数,这其实就是我们递归的实现了。那么它的实现过程又是怎么样的,是如何‘大事化小’的。

这里分成两大步份讲解。下面把四个步骤中的Print函数,分别命名为Print1,Print2,Print3,Print4。

递推:

第一步我们输入1234输入Print1函数里,通过if语句判断大于9进入语句,里面又是Print函数,但传入的参数变成n\10。所以传入Print2函数的n变成了123。

第二步Print2接收到123还是大于9,进入Print3函数,变成了12。

第三步Print3接收到12还是大于9,进入Print4函数,变成了1。

第四步Print4接收到1,要小于9,不进入if语句,直接到了printf语句,打印1跟10求模的值,1。

回归:

第五步因为我们是一步步下来的,之前的Print1,2,3的函数并没有进行完,所以在第四步的Print函数打印完1之后。我们会回到Print3函数,这个时候已经把if语句走完了,到了printf语句,又因为这个时候n是等于12的,所以n%10是等于2的。依此类推,回到Print2就打印3。Print1就打印4。

程序结束。

上面的过程可以看到,递归其实是分为两个步骤进行的,首先是递推,把大问题化成一个个小问题。接着就是回归,把问题一个个解决。

那么什么样的才算是一个合格的递归呢。递归必须满足俩个条件。

  1. 存在限制条件,当满足这个限制条件的时候,递归结束。

  1. 每次的递归调用都应该更加接近限制条件。

ok,已经把递归基本内容说的差不多了。让我们进入今天的正题:斐波那契数列。

简单介绍一下斐波那契数列。

斐波那契数列(Fibonacci sequence), 斐波那契数列指的是这样一个数列: 1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584......

观察斐波那契数列数列可以看到除了前两个数之外,它的每一个数都等于它的前两个数相加。举例第5个数:5,它等于3加2,而三又等于它前面两个数1加2,2又等于它的前两个数相加1和1。这样的过程就是递归,一直不断的划分下来其实到最后就看有几个1相加,让我来实现一下。

可以看到这里我的限制条件就是n<=2的时候结束递归,因为我发现的规律是从第三个数开始的,所以递归只能从第三个数开始。满足第一个条件。在看看else,我每次返回的就是这个数的前两个值相加。只要返回的这两个值不大于2,就一直返回。第一步用了两次这个函数,然后分解的来个函数再次分解成四个函数,然后再分解为八个函数......可以发现这不是这次数不是2的n次方吗。那么可想而知,涉及到次方的话,这个数字一但大起来,就会非常的大,你程序运行的就非常慢。我尝试了一下,真的半天没有反应。

可以看一下这个过程,重复的数字有多少,这样的效率太低了。如果还不够直观的话,我再写一个函数给你们看看。

这里的意思是2被统计过多少次。可以看到一个非常大的数字。如果数字再大的话,可以就会造成栈溢出了。所以这个递归虽然可以实现这个过程,但不是很好,这个时候就尽量不要用递归了。可以考虑使用迭代的方法去实现这个过程。

迭 代

这里我实践了一下,同样是数字40,迭代会比递归快很多。你们有兴趣也可以实践一下,不想手打的话。可以找我要发源码。

这里迭代的实现过程是这样的我把斐波那契数列前两个数直接设置为a,b。作为整个函数的基础。斐波那契数列中1,1同样是基础。再设置一个值作为‘第三个数’。直接把它设置为1,因为如果你输入1或者2的时候,我就直接返回1了。设置成其他的话,就会出错。这时候实现过程是这样的:

首先输入的数字大于等于3,不管它多少次。进入到循环之后,我从斐波那契数列的第三个数开始算起,等于1+1,然后把第二个数的值b=1赋给第一个数a。再把算出来的第三个数的值c=2赋给b。这时候第一个和第二个值就发成变化,各自前移了一步。每进行完一次循环之后就n--。n就是代表了你要前移的步数,也就是你想求的值的位置。按照这个步骤一直循环,一直前移。比起递归大大增加了效率。

这就是我有关递归和迭代的理解,如果哪里讲错了,欢迎指出,我会进行改正。谢谢。

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
非常好的问题!斐波那契数列是由0、1开始,后面的每一项都是前两项的和。所以斐波那契数列的前几项如下: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144... 接下来,我会先讲解如何用递归实现斐波那契数列的第n项,然后再介绍如何用迭代实现递归实现 递归实现斐波那契数列的思路很简单:对于斐波那契数列的第n项,我们可以先求出第n-1和n-2项,然后将它们相加即可。而对于第n-1和n-2项,我们同样可以用同样的方式求出。 根据递归的思路,我们可以定义一个递归函数,代码如下: int fibonacci_recursion(int n) { if (n <= 0) return 0; else if (n == 1) return 1; else return fibonacci_recursion(n-1) + fibonacci_recursion(n-2); // 递归调用 } 上面的代码先判断了一下n的值是否小于等于0或等于1,这是为了避免递归陷入无限循环。如果n等于0,则返回0;如果n等于1,则返回1。否则,我们将递归调用fibonacci_recursion(n-1)和fibonacci_recursion(n-2),并将它们相加返回。 但是,这个递归实现有一个很明显的问题:当n比较大时,递归会变得非常的深,这会导致函数调用栈溢出。因此,我们需要用迭代来替代递归迭代实现 迭代实现斐波那契数列的思路与递归实现基本一致,只是用循环替代了递归。我们首先初始化前两项为0和1,并用循环依次计算出后面的每一项。 具体实现如下: int fibonacci_iteration(int n) { if (n <= 0) return 0; else if (n == 1) return 1; int a = 0, b = 1, c; for (int i = 2; i <= n; i++) { c = a + b; a = b; b = c; } return b; } 上面的代码中,我们先判断了一下n的值,如果n等于0,则返回0,如果n等于1,则返回1。然后,我们用a初始化为0,b初始化为1,依次计算出后面的每一项。具体实现如下: - 首先,我们将a和b的值相加,将结果赋值给变量c。 - 然后,将b的值赋给a,将c的值赋给b。 - 最后,当i>n时,返回变量b即可。 这个迭代实现的想法很简单,而且循环的次数只有n-1次,因此它是比递归实现更加高效的一种实现方法。 总结 斐波那契数列是一道经典的算法题,也是算法和程序设计中很重要的一个概念。我们用递归迭代分别实现斐波那契数列的第n项,递归实现简单,但会导致函数调用栈溢出;迭代实现思路相对复杂,但是效率更高,不会出现函数调用栈溢出的问题。我希望我的回答能够帮助你更好地理解斐波那契数列
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值