©作者:凡人编程传
©系列:C语言初阶(适合小白入门)
©说明:以凡人之笔墨,书写未来之大梦

文章目录

  • ₪前言
  • ₪求一个数的阶乘(递归实现)
  • ₪求斐波那契数列的第n项
  • ₪结言

₪前言

这一节,咱们把递归的最后两道题讲了,递归这个知识点的内容就全部完成了,好了,废话不多说,咱们直接进入正题了!

₪求一个数的阶乘(递归实现)

这道题熟悉吧,在循环结构的文章里面的练习题讲过的。不过这次咱们要用递归来实现。那么怎么实现呢?

这里再介绍一下递归的执行过程:递归氛围分为两个执行过:回推和递推。
1.回推:回推就是根据要解决复杂的问题去找到类似于大复杂问题,简单问题最基本的解。这个过程需要系统内存的栈存储临时变量的值;
2.递推:递推就是根据找到简单问题的解去得到复杂问题的解,这个过程是逐步释放之前栈空间所保存的变量,直到得到复杂问题的解。

那么这个问题的回推过程是什么呢?看例子吧:

根据数学知识,一个数的阶乘是上一个数的阶乘与这个数字本身相乘。如3!(这里的感叹号是数学里面的阶乘符号,不是逻辑非)为3!=3*2!

那么我们要求n的阶乘也就是如下:

n!=n * (n-1)
(n-1)!=(n-1) * (n-2)!
(n-2)!=(n-2) * (n-3)!

2!=2 * 1!
1!=1* 0!;
0! = 1 (0是最小的阶乘数,规定值为1)

从上述例子可以看出,如果想要知道n的阶乘,那么就必须要先知道(n-1)! * n,想要知道(n-1)!就必须先要知道,(n-2)! * n(n-1)。这个过程也就是函数自己调用自己的过程,以此类推,直到我们回推到知道的最基本知识点0!=1,就可以开始递推了。

递推:
回推到我们知道的0!=1;

0!=1;
1!=1 * 1 (1!=1 * 0!)
2!=2 * 1. (2!=2 * 1!)
3!=3 * 2 (3!=3 * 2!)

n!=n*(n-1)!

根据0!=1这个已知的基本条件,得到1!,2!,3!..最终得到n!

另外再说一点,n是可能是负数的,因为最小的阶乘是0!。所以写代码时注意罗列分支。

有了以上知识,我们就知道代码怎么写了。

code:

#include<stdio.h>
int fac(int k)
{if(k<0){return -1;  //没有负数的阶乘}if(0==k){return 1;   //0的阶乘为1}else{return k*fac(k-1);}
}
int main()
{int n;scanf("%d",&n);int t=fac(n);if(t<0){printf("参数错误!没有负数的阶乘!\n");}else{printf("%d!=%d",n,fac(n));}return 0;
}

测试结果:

₪求斐波那契数列的第n项

这道题和上一道题很类似,根据数学知识可以知道基本条件,斐波那契数列的前两项都为1,且从第3项开始,每项是前两项的和。

如:

2=1+1
3=2+1
5=2+3

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

可以看出,每一项都是前两项之和。那么我们就可以根据这个规律和一个已知的基本条件前两项是1,来进行回推和递推了。

回推:
n=(n-1)+(n-2)
(n-1)=(n-3)+(n-2)
(n-2)=(n-4)+(n-3)

这里我们画一个图来更容易理解;
这里假设n为50

我们可看到,1个数去回推另两个数来求和,还有就是44这个数被重复计算了很多次。这还只是第4次回推,要一直推到1,也就是2的49次方,那这些数据要被重复计算多少次?这是否会导致我们的效率低。

递推:
递推就是一直回推到那个已知条件前两项为1,就可以开始求第3项的(1+1=2),第4项(2+1=3)以此类推到n。也就是上图的倒过来开始求项。

有了以上知识,就可以写出代码了

code:

#include<stdio.h>
int Fib(int k)
{if(k>2)     //不是前两项,从第3项开始{return Fib(k-1)+Fib(k-2);}else if(k>=1){return 1;   //前两项是1}
}
int main()
{int n;scanf("%d",&n);printf("第%d项=%d",n,Fib(n));return 0;
}

测试结果:

但是递归用到这种需要大量重复计算的题上效率太低了。如果要求的项大了计算机是需要很久才算得出来的,我们来测试求第40项一下第3项2被重复计算了多少次

code

#include<stdio.h>
int count=0;        //定义全局变量来增大生命周期,保证count在整个项目中有效
int Fib(int k)
{if(k==3){count++;}if(k>2)     //不是前两项,从第3项开始{return Fib(k-1)+Fib(k-2);}else if(k>=1){return 1;   //前两项是1}
}
int main()
{int n;scanf("%d",&n);printf("第%d项=%d\n",n,Fib(n));printf("count=%d",count);return 0;
}

测试结果:

三千多万次!可见这个时间复杂度有多差,效率高低一看便知。

那么咱们这道题能不能换个写法?能!斐波那契数列反正是的第n项反正是前两项的和嘛。咱们从前往后加不就完了,这样就可以避免多次重复计算一个数字,不用像递归一样去找前n个数回来计算又重新算那个数。

循环来写的主要关键就是从前往后面算的时候,先把第n个数用(n-1)+(n-2)算出来,然后要求第n+1个数的时候把n-1改为n-2,n-2又改为n.可能有点看不懂,没关系咱们看图。


这是求第3项

求第4项

还有注意,每次循环就算出来一个数,那么就离n更近了一步最后求n只需算到n-1即可与n-2相加得到n,有了以上知识就可以敲代码了:

code:

#include<stdio.h>
long long Fib(int k)        //这里测试第50项,防止整形溢出所以设为long long 类型
{long long a=1,b=1,c=1;        //已经知道前两项,c设1应付当n<-2时也就是求前两项为1,所以设为1while(k>2){c=a+b;a=b;b=c;k--;}return c;}
int main()
{int n;scanf("%d",&n);printf("第%d项=%lld\n",n,Fib(n));return 0;
}

运行结果:

这时候得出结果就很快了,因为计算机不需要大量重复计算了。

₪结言

好了,函数递归这一章节的内容到此结束,希望你有收获,期待下一章节的数组吧!

【C语言】剖析函数递归(3)相关推荐

  1. 【C语言】剖析函数递归(2)

    ©作者:凡人编程传 ©系列:C语言初阶(适合小白入门) ©说明:以凡人之笔墨,书写未来之大梦 文章目录 ₪前言 ₪自定义实现strlen函数(不能创建临时变量) ₪结言 ₪前言 这一节我们继续讲函数递 ...

  2. 计算机二级C语言考的函数,【帮考网】2012计算机等级二级考试C语言:函数递归...

    一.栈 在说函数递归的时候,顺便说一下栈的概念. 栈是一个后进先出的压入(push)和弹出(pop)式数据结构.在程序运行时,系统每次向栈中压入一个对象,然后栈指针向下移动一个位置.当系统从栈中弹出一 ...

  3. C语言使用函数递归实现n的k次方(包括负数次方)

    文章目录 前言 代码示例 实现效果 前言 题目要求:使用C语言写一个函数,能够使用函数递归实现计算n的k次方,包括负数次方. 题目分析: 要求使用递归,先求出递归公式,假设我们的函数是 myPow(i ...

  4. C语言程序设计 函数递归调用示例

    函数递归调用示例(教材习题5.3,运行结果012345) #include<stdio.h> void fun(int k); void main() {   int w=5;   fun ...

  5. 【C语言】函数递归(详解)

    文章目录 函数递归 什么是递归? 递归的俩个必要条件 代码引例1 栈溢出(Stack Overflow) 合理使用递归 代码引例3 代码引例4 解释要合理使用递归 结束语 函数递归 程序调用自身的编程 ...

  6. 【C语言】函数递归详解

    函数递归 1. 什么是函数递归 2. 递归的两个必要条件 2.1 练习1:打印一个数的每一位 2.2 练习2:求字符串长度(strlen 模拟实现) 3. 递归与迭代 3.1练习3:求 n 的阶乘(不 ...

  7. 学点 C 语言(35): 函数 - 递归

    1. 递归就是: 函数自己调用自己 这是一个最简单的递归, 不过它会一直执行, 可用 Ctrl+C 终止. #include <stdio.h>void prn(void) {printf ...

  8. [日常] Go语言圣经-函数递归习题

    练习 5.1: 修改findlinks代码中遍历n.FirstChild链表的部分,将循环调用visit,改成递归调用. 练习 5.2: 编写函数,记录在HTML树中出现的同名元素的次数. 练习 5. ...

  9. C语言_函数递归举例

    1.递归和非递归分别实现求第n个斐波那契数. //求第 n 个斐波那契数 #include <stdio.h> #include <stdlib.h>int Fib1(int ...

最新文章

  1. git服务器搭建问题
  2. 浏览器及时感知服务端数据变化的方式
  3. 【转载】设计模式_六大原则(学习)
  4. SQL批量更新DateTime中的年、月、日
  5. 目标检测——从RCNN到Faster RCNN 串烧
  6. 刷题笔记2020-06-26
  7. mysql中时间处理函数_基于mysql时间处理函数的应用详解
  8. 在linux系统中下载thchs30,aishell数据处理为thchs30格式
  9. dedecms 文章列表被加粗的加爵办法
  10. [每日一氵] linux 批量删除某个名字的文件夹
  11. Fcitx使用搜狗词库与皮肤
  12. 鸿蒙系统研究第一步:从源码构建系统镜像
  13. CSS Sprite
  14. Zabbix系列:设置动态监控告警时间范围
  15. 【ML特征工程】第 7 章 :通过K-Means 模型堆叠进行非线性特征化
  16. 复杂大脑网络的结构和功能
  17. 机器学习之选择小样本交叉验证训练模型并使用精确率、召回率、F1分数和AUC值、画出ROC曲线评估
  18. 小黑为四川大学实习金融专业同学解决了困扰好久的一个代码小bug,获得成就感,和清华实习同学约饭啦(被请客),继续向前的leetcode之旅:145. 二叉树的后序遍历
  19. 区块链学习(8) EOS环境安装和智能合约部署实战(绝对干货!)
  20. 互联网小拼,这一生的故事,你要看看吗《打工人的那些事》

热门文章

  1. 什么是 Web 应用防火墙(WAF)?
  2. DRGs与RBRVS的理解
  3. 一致性算法之Raft算法
  4. 玩树莓派(raspberry pi) 2/3 raspbian的遇到的一些问题
  5. 正弦和余弦(sin和cos)
  6. SIM7600X常用指令
  7. 超声图像散斑去噪方法
  8. php 条形码在线怎么生成,php实现在线生成条形码示例分享(条形码生成器)
  9. linux安装gfortran出现错误,Fortran gfortran linux中出现“Segmentation Fault(core dumped)”错误...
  10. 第四周项目三计算并联电阻