首页 > 其他分享 >关于我、重生到500年前凭借C语言改变世界科技vlog.8——函数递归

关于我、重生到500年前凭借C语言改变世界科技vlog.8——函数递归

时间:2024-10-22 23:20:10浏览次数:3  
标签:10 函数 递归 int C语言 printf Print vlog.8 500

在这里插入图片描述

文章目录

1.递归的介绍

在 vlog.2 的 printf 函数的返回值举例中,我们使用多次递归的方式实现了同一个函数的返回值调用,但这只是一个简易的递归,不算真正意义上的递归,那么什么是递归?

在C语言中,递归就是函数自己调用自己,如果函数的递归没有限制条件,一直无限循环调用下去,代码最终就会陷入死循环,导致栈溢出(Stack overflow)

递归就是递推的意思,递归的思考方式就是将大事化小,将复杂的程序化成简单的代码格式,也就是化成一个个子问题求解,知道子程序不再被分解,递归就结束了

2.递归的限制条件

值得注意的是,递归也存在限制条件

• 递归存在限制条件,当满足这个限制条件的时候,递归便不再继续
• 每次递归调用之后越来越接近这个限制条件

3.递归实战应用

3.1 求 n 的阶乘

由数学知识可知:n!= n ∗ (n−1)! 当 n == 0 的时候,此时 n 的阶乘是 1 ,n > 0时阶乘可根据公式计算

那么我们可以写出阶乘函数 Fact ,Fact(n) 是求 n 的阶乘,那么Fact(n-1)就是求 n-1 的阶乘
此处不考虑 n 过大导致栈溢出的情况,只考虑合理范围内的 n

 #include <stdio.h>
 int Fact(int n)
 {
 if(n==0)
 return 1;
 else
 return n*Fact(n-1);
 }
 int main()
 {
 int n = 0;
 scanf("%d", &n);
 int ret = Fact(n);
 printf("%d\n", ret);
 return 0;
 }

该程序的递归思想可以根据画图很容易的理解
在这里插入图片描述

3.2 顺序打印一个整数的每一位

输入⼀个整数m,按照顺序打印整数的每⼀位
如果n是⼀位数,n的每⼀位就是n自己
n是超过1位数的话,就得拆分每⼀位
比如:

1234%10就能得到4,然后1234/10得到123,这就相当于去掉了4
然后继续对123%10,就得到了3,再除10去掉3,以此类推
不断的 %10 和 /10 操作,直到1234的每一位都得到
但是这里有个问题就是得到的数字顺序是倒着的

假设我们用函数Print(n)打印n的每一位
那么我们知道1234 % 10 = 4,1234 / 10 = 123

Print(1234)就可以拆分为两步:

  1. Print(1234/10) //打印123的每⼀位
  2. printf(1234%10) //打印4

以此类推,利用递归思想

    Print(1234)
 ==>Print(123)                   +printf(4)
 ==>Print(12)          + printf(3)
 ==>Print(1) + printf(2)
 ==>printf(1)

直到被打印的数字变成一位数的时候,就不需要再拆分,递归结束:

 void Print(int n)
 {
   if(n>9)
   {
      Print(n/10);
   }
   printf("%d ", n%10);
 }
 int main()
 {
     int m = 0;
     scanf("%d", &m);
     Print(m);
     return 0;
 }

这里的函数不断地调用,当函数调用完之后依次从最后一个子程序往第一个程序打印

4.递归与迭代

Fact函数是可以产生正确的结果,但是在递归函数调用的过程中涉及一些运行时的开销

在C语言中每一次函数调用,都需要为本次函数调用在内存的栈区,申请一块内存空间来保存函数调
用期间的各种局部变量的值,这块空间被称为运行时堆栈,或者函数栈帧。
函数不返回,函数对应的栈帧空间就⼀直占用,所以如果函数调用中存在递归调用的话,每⼀次递归
函数调用都会开辟属于自己的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间,
所以如果采用函数递归的方式完成代码,递归层次太深,就会浪费太多的栈帧空间,也可能引起栈溢
出的问题,而且也很耗时间(后期将推出函数栈帧专题)

通常如果使用递归不合适,就可以使用迭代的方式,那什么是迭代呢?
迭代简单来讲就是用循环的方式运行

举个例子:求第 n 个斐波那契数
在这里插入图片描述
如果使用的是递归的方法的话,层次会非常深,冗余的计算会非常多

#include <stdio.h>
 int count = 0;
 int Fib(int n)
 {
 if(n == 3)
     count++;//统计第3个斐波那契数被计算的次数
 if(n<=2)
     return 1;
 else
     return Fib(n-1)+Fib(n-2);
 }
 int main()
 {
 int n = 0;
 scanf("%d", &n);
 int ret = Fib(n);
 printf("%d\n", ret);
 printf("count = %d\n", count);
 return 0;

根据 count 的次数,在计算第40个斐波那契数的时候,使用递归方式,第3个斐波那契数就被重复计算了39088169次,这些计算是非常冗余的。所以斐波那契数的计算,使用递归是非常不明智的,我们就得想迭代的方式解决

那么迭代的话

int Fib(int n)
 {
 int a = 1;
 int b = 1;
 int c = 1;
 while(n>2)
 {
 c = a+b;
 a = b;
 b = c;
 n--;
 }
 return c;
 }

不难看出,似乎用迭代的方式去实现这个代码,效率就要高出很多了,但同时我们也不要一直使用,会容易出现程序错误

5.递归经典问题的拓展

青蛙跳台阶问题
汉诺塔问题

这两个问题将在下一期vlog拓展推出,欢迎大家看我的下一期推文

希望读者们多多三连支持

小编会继续更新

你们的鼓励就是我前进的动力!

在这里插入图片描述

标签:10,函数,递归,int,C语言,printf,Print,vlog.8,500
From: https://blog.csdn.net/Zero_VPN/article/details/143168763

相关文章

  • 实验三 C语言函数应用编程
    任务一#include<stdio.h>charscore_to_grade(intscore);//函数声明intmain(){intscore;chargrade;while(scanf("%d",&score)!=EOF){grade=score_to_grade(score);//函数调用printf("分数:%d,等级:%c\n......
  • 【趣学C语言和数据结构100例】
    #1024程序员节|征文#【趣学C语言和数据结构100例】问题描述56.设将n(n>1)个整数存放到区带头结点处单链表乚中,设计算法将L中保存的序列循环石移k(0<k<n)个位置。例如,若k=1,则将链表(0,1,2,3}变为{3,0,1,2}57.设有一个带头结点的非循环双链表L,其每个结点中除有pre、da......
  • 数据结构 链表 C语言
    数据结构第二章的链表//线性表的链式存储#include<stdlib.h>#include<stdio.h>typedefintElemType;typedefstructnode{ElemTypedata;structnode*next;}Node,*LinkList;//初始化空的单链表voidInitList(LinkList*L){*L=(LinkLis......
  • 奇偶序号分割单链表(C语言)
    算法思想:要想将单链表L按照奇偶序号分割为两个单链表A(奇),B(偶),我们便可以定义一个变量来记录当前遍历的结点序号的奇偶,两个指针ra,rb,ra负责将奇数位置结点赋到A中,rb同理核心代码:voiddevide(LinkListL,LinkListA,LinkListB){intindex=1;LNode*p=L->next;......
  • C语言学习第9天
    目录字符数组概念定义和初始化定义:初始化方式:二维字符数组字符串操作函数头文件:#include函数名:strlen(s)sizeof()和strlen()的区别函数名:strcmp(s1,s2)函数名:strcpy(s1,s2)函数名:strcat(s1,s2)函数名:void*memset(void*s,intc,size_tn);字符串输入gets()......
  • C语言中的初始化是什么意思
    在C语言中,初始化是指在定义变量时为其赋予初值的过程。通过初始化,可以确保变量在使用之前具有已知的初始值,避免了未初始化变量的不确定行为。初始化可以在变量定义时直接赋值,也可以通过赋予默认值或调用特定的初始化函数来完成。C语言中的初始化在C语言中,初始化是指在定义变......
  • C语言使用指针作为函数参数,并利用函数嵌套求输入三个整数,将它们按大到小的顺序输出。(
    输入三个整数,要求从大到小的顺序向他们输出,用函数实现。   本代码使用到了指针和函数嵌套。   调用指针做函数ex,并嵌套调用指针函数exx在函数ex中。(代码在下面哦!)一、关于函数 ex  1. 这个函数接受三个指针参数 int*p1 、 int*p2 和 int*p3 ,分别指......
  • C语言中如何实现链表
    文章开头:在C语言中,实现链表主要涉及以下几个步骤:定义链表的结点、创建链表、添加链表结点、删除链表结点、查找链表结点、打印链表和释放整个链表。我们以一个单链表为例,每一个结点包括两部分:一部分是数据域,存放元素的值;另一部分是指针域,存放下一个结点的地址。创建链表首先需要......
  • 如何在C语言中使用结构体进行数据管理
    #如何在C语言中使用结构体进行数据管理在C语言中,结构体是一种方便、高效的数据管理方式。结构体允许用户将不同类型的数据项组织在一起,它们常被用于代表一个有实体意义的数据集合。在使用结构体进行数据管理时,关键优势包括数据封装、类型安全、易于维护性。数据封装意味着可以......
  • 【C语言】文件操作(2)(文件缓冲区和随机读取函数)
    文章目录一、文件的随机读取函数1.fseek函数2.ftell函数3.rewind函数二、文件读取结束的判断1.被错误使用的feof2.判断文件读取结束的方法3.判断文件结束的原因feofferror判断文件读取结束原因示例三、文件缓冲区一、文件的随机读取函数  在上一篇的文章中,我......