作者:几冬雪来
时间:2023年2月2日
内容:C语言函数函数讲解之斐波那契函数篇
目录
前言:
斐波那契函数:
1.什么是斐波那契函数:
2.斐波那契函数怎么实现:
3.如何用C语言书写斐波那契函数:
4.什么时候使用递归,什么时候使用非递归:
结尾:
在上一篇博客中我们将现阶段C语言函数的函数部分内容基本讲解完了,在这几篇博客的学习中,我们更加熟悉了C语言函数的内容,同时也学到了新的知识——函数的递归和迭代,同时也举了不少例子来让我们懂得他们的运作过程,结果和结论。那么今天我们将再举一个例子来模拟我们的函数递归,这一个例子也将作为我们C语言函数函数部分的落幕。
正所谓要写一道题就要了解这道题,相信这道题我们初学者第一次看到的时候,第一反应不会是打开编译器开始写题目,又或者是构思思路。大家看到这道题的反应,应该八九不离十——什么是斐波那契函数,斐波那契函数长什么样。只有这样我们才可以理解题干要让我们干什么,才能真正的开始写题。
现在是互联网的大数据时代,我们也可能通过上往查询我们想要的资料,这里我就在网上寻得了资料。
这篇文章蕴含着大量的专业名词,一大堆的“F()”和数字让我们看得头昏眼花,这个时候我们就需要在这篇文章中找出我们解题的关键信息。
在上面的这篇文章中我们可以看出斐波那契数列是用递归的方法计算出来的,且准确的来说,斐波那契函数指的是一个数列,那么我们将这个数列画下来并逐步进行分析。
这就是我们的斐波那契函数的核心内容,初看十分的无规律以及错杂,但是实际上我们不难看出,在斐波那契函数中,每一项的值,就是前两个数字的值相加的结果。
这个时候有人就发现问题了,这个数列第一项和第二项的值都是1啊,这里斐波那契函数又是怎么计算的?我们可以来一个猜测。
这里根据我自己的理解有两种猜测:
猜测1:其实第一位数是0,但是后来因为一系列我们不知道的问题,所以将0去除了,将第一位变成了1。
猜测2:因为实现斐波那契函数必须有两个值,因为0+1 = 1,感觉没有必要写,所以将前两位直接赋值为1,将0隐藏。
以上均是我的个人理解,如果有人在网上找到了确切的证明的话,那就按照网上的证明去理解。
在讲解完斐波那契函数的概念和实现后,接下来就到了我们最重要的地方了,那就是靠自己来讲斐波那契函数书写出来,那么话不多说,我们就先将函数写出来再来慢慢对其进行讲解和改进。
求第n项的斐波那契函数的值是多少,对比我们上面的数列我们可以看出,第6项的斐波那契函数对应的值是8,这里我们输出的值也是8,刚刚好符合预期。
接下来就来讲讲它的运作过程是怎么样的吧。
首先看我们的“main”函数,是非常中规中矩的写法,这里没有什么要仔细说明的,我们的“a”则是我们要求的第几项的斐波那契函数的值。
接下来就到我们的“he”的函数了。
在“he”函数中,我们的第一个分支语句,当x的值小于等于2的时候,我们都返回1。 这是因为我们斐波那契函数的第一项和第二项的值都为1,所以我们返回值为1。这个相信大家都能理解,那么问题就来到了第二个分支语句。
当第一个条件不满足的时候,我们就现在第一个分支语句。返回值是“he(x - 1)”和“he(x - 2)”,意思就是返回的是“x”前两位斐波那契函数相加的和。我们就用输入值5来举例。
从5开始往下依次分解,5可以分解为3和4,3又可以变为1或者2······,最后将因为当“x”小于等于2的时候返回1,这就是我们的解题过程。那为什么2的时候不再继续分解为1和0呢,因为在第一条分支语句中,当x的值小于等于2的时候,我们返回1,因此我们的2并不用分解,并在最后将我们的2转为1,再进行1的相加。
如图所示,最后我们1的个数为5个,相加结果为5。在斐波那契函数中我们的第5位数的结果对应的是5,所以我们的思路是正确的,大家可以去试试看。
如果我们输入一个很大的值的话,这个代码依旧可以运行吗?我们就用45来试试看结果如何。
程序依旧可以运行,但是在输出结果的时候,编译器会有些许时间停止不动,这是为什么? (注:作者这里因为是图片,所以只能放出结果,编译中无反应的时间要大家去尝试)
我们来看看输出的数的大小,足足有11亿多,虽然编译器算的很快,但是如此之大的数字编译器也不能在一瞬间将它算出来。那这个代码会运行多少次呢?我们对代码稍加改进。
单单是45,编译器中就要进行高达4亿多次的计算。 计算的次数过多,编译器所的速度自然而然的就慢下来了。那在这种情况下,我们如何对代码进行改进呢?
回想我们上一篇博客的一道题。
求一个数的阶乘是多少。
当初我们分别用递归和循环的方式分别对这道题进行了求解,那这道题,我们能不能将我们的递归的方法改为循环的方法来解答呢?那当然是可以的。那应该怎么书写,解题的思路是怎么样的,我们用画一张图来解答。
我们从这张图可以看出,每个数都是由前两位数的和求得,在第3项后,每一项的结果都能由前两项相加的结果得出,那么我们就可以写一个函数。
在“he”函数中,我们创建了3个临时变量,并使用了一个循环语句,循环条件是(x>2)。这是因为只有从第3次开始,我们才能让第3次的结果等于前两次结果之和,在第一次和第二次运算中并没有达成有前两项的条件,因此我们从第3次开始进行。 (这里可能没怎么讲好)
我们将a和b的值初始化为1,由前两项a和b相加的结果赋给c,c就是前两项数之和,然后再将b赋值给a,c赋值给b,然后对x的值进行减减,然后再次循环a加b,再次得到我们新的c,新的c就是我们第二次的结果。持续循环下去,最后循环语句的条件不成立的时候结束循环。 这样子写,同样可以实现我们的斐波那契函数,同时降低了我们的代码运行时间。
从我们上面两题可以看出递归有递归的好处,非递归有非递归的好处,那么我们什么时候使用递归,什么时候使用非递归?一般来说,使用递归有两个条件:
1.该题可以通过递归来实现。
2.递归后不能程序栈溢出的情况。
在满足条件的情况下,我们可以使用递归来求解,在不满足的情况下我们就只能使用非递归的方式来进行求解了。
虽然年已经结束了,但是这几天我还是有很多事情要做,导致博客每次都只能一天也一小部分,中间更是有一天没时间写,因为写得断断续续的,所以导致我前一天的思路和今天的思路没办法正常配对成功,有些部分个人也没怎么理解完全,但是大体内容应该也行有讲出来,希望能对各位有所帮助。