从兔子数列延伸到递归函数的知识
学习之道,重在实践。尤其是像编程这类的技术活,更需要日积月累的实操,不断地试错,发现问题,解决问题。这样一来,编程技术才会真正地有所提升。
因此,C语言学习系列暂时缓一天,做些练习题,让脑子回顾一下之前所学习的内容,也是防止学了新的,忘了旧的。
同时,温故而知新,也可以从旧的知识里面挖掘出新的知识点。
下面就通过练习编程中一道较为经典的题目,来讲一下函数中的递归问题。
兔子数列
兔子数列,又叫斐波那契数列,黄金分割数列。
案例:兔子的繁衍能力是极强的,每 3 个月成熟一次,并会生出 1 对新的小兔子,且之后每个月都会生出 1 对兔子。
前提:兔子开了永生BUFF。
题目:已知有 1 对兔子,求 3 年后,将会拥有多少只兔子?
第一个月,获得了 1 对新生的小兔子。
第二个月,小兔子成熟了,仍然还是 1 对兔子。
第三个月,生了 1 对小兔子,现在是 2 对兔子了。1 对开始繁殖的成熟兔子,1 对小兔子。
第四个月,生了 1 对小兔子,现在是 3 对兔子了。1 对开始繁殖的成熟兔子,1 对还未繁殖的成熟兔子,1对小兔子。
第五个月,生了 2 对小兔子,现在是 5 对兔子。2 对开始繁殖的成熟兔子,1 对还未繁殖的成熟兔子,2 对小兔子。
...
接下来,就是找到其中的规律了。
/*
* 第 1 个月 - 1 对兔子
* 第 2 个月 - 1 对兔子
* 第 3 个月 - 2 对兔子
* 第 4 个月 - 3 对兔子
* 第 5 个月 - 5 对兔子
* ...
* 第 n 个月 - f(n-1)+f(n-2) 对兔子
*/
从第三个月开始,兔子的数量都是前两个月的兔子数量相加的结果。
这里我有两种解题方式,一种是通过 for 循环迭代,一种是使用递归函数。
先来看第一种,用 for循环。
#include<stdio.h>
int main(){// a_count 前两个月的总数// b_count 前一个月的总数// count 当前月的总数int a_count=1, b_count=1, count=0;for(int i=3;i<=36;i++){ // 第三个月开始增长count = a_count + b_count; // 计算当前月的数量// 为了计算下个月的数量,将前两个月额总数都进行替换a_count = b_count;b_count = count;}printf("三年后一共获得%d只兔子。", 2 * count);
}
运行结果:三年后一共获得29860704只兔子。(永生兔子,暴富秘籍!)
第二种,使用递归函数。
#include<stdio.h>
int rabbit(int);
int main(){int count = 0;count = rabbit(36);printf("三年后一共获得%d只兔子。", 2 * count);
}
int rabbit(int n){// 第一个月和第二个月的总数为 1if(n <= 2){return 1;}// 第三个月开始总数等于前两个月的总和return rabbit(n-1)+rabbit(n-2);
}
运行结果:三年后一共获得29860704只兔子。
递归函数相比较循环迭代,整体的代码量要少很多,不需要定义太多的变量。但建议上,还是少用递归函数,这是因为递归函数存在着一个致命缺陷。
下面,来学习一下递归函数。
递归函数
递归,指的是程序调用自身的方法。
递归函数,则是函数自己调用自己。
其主要思想在于化繁为简,大事化小。把一个大型复杂的任务,拆分成一个个小任务进行处理。使用递归,可以用最少的代码解决复杂的问题,大大减少了代码量。
递归和循环迭代很相似,都是重复执行某一段指令,且都需要一个终止条件。
如果没有终止条件,那么这个程序可以说是死的,卡在这个位置,一直执行这个部分的内容,后面就再也执行不了。
所以说,不管是循环还是递归,在每次调用之后,都要趋近于终止条件。
但也有一个本质的区别。递归是有去有回,循环迭代是一去不回的。
就比如,在入口处有人给了你一把钥匙,你拿着钥匙打开第一扇门,发现还有一道门,且还可以用这把钥匙打开。
循环迭代,就好比门口的那个人是一路跟着你,每打开一扇门,你就跟他说这是第几扇门。
递归,就像是懒人,只给你钥匙,然后在入口等待。你需要一扇一扇门开到底,然后走回来一遍一遍的数,回到入口处告诉那个人一共有多少扇门。
从上面这个比喻中可以看出,递归存在的一个缺陷,时间开销巨大。
循环迭代只要走一遍就可以获得结果,而递归函数需要走过去再走回去,相当于是循环迭代所花费的时间两倍。(实际上就不确定是多少倍。)
同时还有这第二个缺陷,内存开销巨大。
拿兔子数列的递归函数举例,假设这里的 n 此时取 5,那么结果返回的值是 rabbit(4)+rabbit(3)。但这不是一个确切的数值,就会暂存在内存中,接着去计算rabbit(4)和rabbit(3)。
直到计算到 rabbit(1) 和 rabbit(2),得到返回值 1,在传回去给前面暂存起来的返回值计算。
而且在运行的这段时间内,前面得到的没有值的返回内容是需要地方暂时存放起来。可想而知,一个递归所需要的内存是得有多大。
而循环迭代,仅是在原本开辟的内存空间里不断对数值进行迭代更新,没有去征用新的内存。
所以一般都是建议程序中能用循环迭代的,尽量用循环迭代。能少用递归的,就少用递归。
总结
使用循环迭代和递归函数的方式实现兔子数列的问题。
递归函数是一种函数自己调用自己的方法,主要思想是将复杂的任务拆分一个个简单的任务分别处理。
递归函数的必要条件是,必须要有一个终止条件,且每次调用都要趋近于终止条件。
但递归函数是一种内存和时间开销都非常巨大的方法,一般建议能用循环迭代用循环,尽可能少用递归函数。
从兔子数列延伸到递归函数的知识相关推荐
- 递归函数输出斐波那契数列-黄金分割数列-兔子数列(python)
递归函数输出斐波那契数列-黄金分割数列-兔子数列(python) 斐波那契数列介绍 数学家莱昂纳 多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为"兔 ...
- 兔子数列规律怎么讲_探究“兔子数列”提升数学能力
倪丽君 [摘 要]在解决问题过程中,教师一般根据问题类型进行模式教学,而建模的过程中,能力的培养则是数学教学的重点.以斐波那契数列的教学为例,通过外在的操作活动,培养学生的数学应用能力,让学生经历从形 ...
- 【C语言】案例二十五 兔子数列(斐波那契数列)
案例描述 兔子数列又称斐波那契数列,黄金分割数列,具体描述如下:一对兔子在出生两个月后,每个月都能生出一对小兔子,现有一对刚出生的兔子,假设所有兔子都不死,那么一年后有对少只兔子? 案例分析 n表示月 ...
- php算法求出兔子数列,PHP算法:斐波那契数列的N种算法
前言 前段时间,遇到优化计算斐波那契数列的常规递归方法,但是一时间并没有及时想到很好的方法,所以后面查找了相关资料,总结了多种计算解法,所以分享出来,和大家一起交流学习. 斐波那契数是什么 斐波那契数 ...
- OJ1055: 兔子繁殖问题(C语言计算斐波那契数列/“兔子数列”)
题目描述 这是一个有趣的古典数学问题,著名意大利数学家Fibonacci曾提出一个问题:有一对小兔子,从出生后第3个月起每个月都生一对兔子.小兔子长到第3个月后每个月又生一对兔子.按此规律,假设没有兔 ...
- 兔子数列规律怎么讲_神奇兔子数列
假设第1个月有1对刚诞生的兔子,第2个月进入成熟期,第3个月开始生育兔子,而1对成熟的兔子每月会生1对兔子,兔子永不死去--那么,由1对初生兔子开始,12个月后会有多少对兔子呢? 兔子数列即斐波那契数 ...
- 兔子数列 - C语言
兔子数列 兔子数列的起源 公元13世纪,在意大利有一位天才的数学家名字叫斐波那契,他在一本<算盘之书>的著作里记载了这样一道数学题:有一对兔子,每一个月可以生下一对小兔子,而且假定小兔子在 ...
- 【递推】HDU -2018 母牛的故事斐波那契兔子数列
函数之递归的应用 母牛的故事 (这个问题还有很多类似的,比如种树,每一年种的树品质在改变,当然区别在于树不能生孩子.. 相应的人类达到法定年龄就可以生孩子,这个和母牛问题一样,只不过时间间隔变化了. ...
- 兔子数列(斐波拉契数列)javscript的三种写法
斐波那契数列(Fibonacci sequence),又称黄金分割数列.因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为"兔子数列&qu ...
最新文章
- hive-数据倾斜记录分享
- 模块化编程AMDCommonJS
- 华为SAP解决方案为海澜之家带来新的科技创新
- java webservice https_WebService的HTTPS访问——解决PKIX错误 | 字痕随行
- CSDN编程挑战——《交替字符串》
- 笔记(2015-07-24)
- Oracle-11g 基于 NBU 的 rman 冷备份及恢复
- 在 MyEclipse 5.1GA 上使用 XFire 编写 Web Service
- 三维数学基础(一)坐标系、向量、矩阵
- Android未发现目标设备,Android设备不会显示为Unity3d调试的目标
- android 智能手机usb驱动程序,华为手机usb驱动下载
- AI改变现代商业的25种方式
- SQL Server 2019的下载与安装
- 如何安装iOS 13 、 macOS Catalina 、watchOS 6 、 tvOS 13 或 iPadOS Beta
- stm32 app 连上阿里云
- Android版添加phonegap-百度社会化分享插件教程
- TCPIP卷一(8):EIGRP的组建和邻居状态机
- 永顺一中2021高考成绩查询入口,2017年高考永顺传来喜报
- label 标签属性的总结归纳
- Python爬虫:史上最详细的Python爬虫库urllib讲解,绝对经典,值得收藏