[C语言学习]----函数递归(超详细!!!)

article/2025/9/12 4:35:10

本篇介绍的是C语言函数递归的详细知识

程序的艺术来源于生活

目录

7. 函数递归

7.1递归是什么

7.2 递归的两个必要条件

7.2.1练习1(详细讲解)

7.2.2练习2(详细讲解)

7.3 递归与迭代

 7.3.1练习3(详细讲解)

7.3.2 练习4(详细讲解)

7.4练习3,4中出现的问题


7. 函数递归

7.1递归是什么

程序调用自身的编程技巧称为递归

函数自己调用自己


递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解

递归策略

只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。


递归的主要思想在于:把大事化小

例(史上最简单的递归):

#include<stdio.h>
int main()
{printf("Hello World\n");main();
}

先一直打印 Hello World,最终程序挂掉

7.2 递归的两个必要条件

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

7.2.1练习1(详细讲解)


接受一个整型值(无符号),按照顺序打印它的每一位。
例如:
输入:1234,输出 1 2 3 4

 

我们的第一想法是先让

	1234%10 = 41234/10=123123%10=3123/10=1212%10=212/10=11%10=11/10=0

这样能够得到数字的每一位,然后我们再打印出来

#include<stdio.h>
int main()
{unsigned int num = 0;scanf("%u", &num);while (num){printf("%d ", num % 10);num = num / 10;}return 0;
}

程序一进行我们发现输出的结果与题目中的不同,需要我们用递归来进行

递归的思想是将大事化小

我们定义一个print()函数,它的功能是按照顺序打印num的每一位

打印1234的每一位:print(1234)

打印1234的每一位,我们可以先打印123的每一位再打印4

打印123的每一位:我们可以先打印12的每一位print(12)再打印3 

打印12的每一位:我们可以先打印1的每一位print(1)再打印2 

最后输出打印1 2 3 4

程序:

print(1234)
print(123) 4
print(12) 3 4
print(1) 2 3 4
最终输出:1 2 3 4

num<10的时候我们只需要直接打印就行

num>=10.我们就需要分着打印 

代码实现:

#include<stdio.h>
void print(unsigned int n)
{if (n < 10)//限制条件printf("%d ", n);else{print(n / 10);//每次递归调用之后越来越接近这个限制条件printf("%d ", n%10);}
}
int main()
{unsigned int num = 0;scanf("%u", &num);print(num);return 0;
}


当然也有更简单不冗余的写法:

#include<stdio.h>
void print(unsigned int n)
{if (n > 9)限制条件{print(n / 10);每次递归调用之后越来越接近这个限制条件}printf("%d ", n % 10);
}
int main()
{unsigned int num = 0;scanf("%u", &num);print(num);return 0;
}

7.2.2练习2(详细讲解)

编写函数(不允许创建临时变量),求字符串的长度

铺垫(编写函数(允许创建临时变量),求字符串的长度):

我们有一个专门求字符串长度的库函数:strlen

 首先我们先创建一个字符数组

char arr[] = "abc";

再用strlen

#include<stdio.h>
#include<string.h>
int main()
{char arr[] = "abc";int len = strlen(arr);//传递的首元素地址printf("%d", len);return 0;
}

这题是让我们创建一个函数my_strlen,模仿写一个strlen函数

非递归方式:

#include<stdio.h>
int my_strlen(char* str)
{int count = 0;while (*str != '\0'){count++;str++;}return count;
}
int main()
{char arr[] = "abc";int len = my_strlen(arr);printf("%d", len);return 0;
}

 编写函数(不允许创建临时变量),求字符串的长度(递归方式):

如果第一个字符不是'\0',说明字符串里面至少包含一个字符

所以当第一个元素不是'\0'的话

求my_strlen("abc")就可以看成求1+my_strlen("bc")的长度

求1+my_strlen("bc")的长度就可以看成 求1+1+my_strlen("c")的长度

求1+1+my_strlen("c")的长度就可以看成 求1+1+1+my_strlen(" ")的长度

最后算出来等于3

 代码实现:

#include<stdio.h>
int my_strlen(char* str)
{if (*str != '\0')return 1 + my_strlen(str + 1);//传递下一个字符的地址elsereturn 0;
}
int main()
{char arr[] = "abc";int len = my_strlen(arr);printf("%d", len);return 0;
}

7.3 递归与迭代

 7.3.1练习3(详细讲解)

求n的阶乘。(不考虑溢出

递归:

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

但当我们输入大的数字时,递归会算不出结果

所以这道题最好用非递归的方式(迭代)计算:
(循环是一种迭代)

#include<stdio.h>
int Fac1(int n)
{int i = 0;int ret = 1;for (i = 1; i <= n; i++){ret = ret*i;}return ret;
}
int main()
{int n = 0;scanf("%d",&n);printf("%d",Fac1(n));return 0;
}

7.3.2 练习4(详细讲解)

求第n个斐波那契数。(不考虑溢出)

 什么是斐波那契数列

分为两部分 

 

 按照公式写代码

#include<stdio.h>
int Fib(int n)
{if (n <= 2)return 1;elsereturn Fib(n - 1) + Fib(n - 2);
}
int main()
{int n = 0;scanf("%d",&n);printf("%d",Fib(n));return 0;
}

7.4练习3,4中出现的问题

但是我们发现这样会有问题:
 

  • 在使用 Fib 这个函数的时候如果我们要计算第50个斐波那契数字的时候特别耗费时间。
  • 使用Fac函数求10000的阶乘(不考虑结果的正确性),程序会崩溃。

原因是因为

Fib 函数在调用的过程中很多计算其实在一直重复
那我们如何改进呢?

  • 在调试 Fac函数的时候,如果你的参数比较大,那就会报错: stack overflow(栈溢出)这样的信息。
  • 系统分配给程序的栈空间是有限的,但是如果出现了死循环,或者(死递归),这样有可能导致一直开辟栈空间,最终产生栈空间耗尽的情况,这样的现象我们称为栈溢出

如何解决上述问题

1. 将递归改写成非递归。
2. 使用static对象替代 nonstatic 局部对象。在递归函数设计中,可以使用 static 对象替代
nonstatic 局部对象(即栈对象),这不仅可以减少每次递归调用和返回时产生和释放 nonstatic 对象的开销,而且 static 对象还可以保存递归调用的中间状态,并且可为各个调用层所访问

非递归方式解决斐波那契数列

#include<stdio.h>
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;
}int main()
{int n = 0;scanf("%d", &n);int ret = Fib(n);printf("%d\n", ret);return 0;
}

提示:


1. 许多问题是以递归的形式进行解释的,这只是因为它比非递归的形式更为清晰。
2. 但是这些问题的迭代实现往往比递归实现效率更高,虽然代码的可读性稍微差些。
3. 当一个问题相当复杂,难以用迭代实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开销

 

结语:本篇是函数递归的知识,如果本篇对你有用,请大家点赞关注!!!

现在关注是新粉,以后就是老粉了

下期预告:数组

感谢你的观看,我们下期再见


http://chatgpt.dhexx.cn/article/05e37r2h.shtml

相关文章

五、需求分析建模之数据库建模

1. 了解E-R图在基于数据库的软件系统分析中的作用。 2. 复习并深化理解E-R图的相关概念。 3. 学习从实际应用问题中抽取E-R模型的方法。 4. 掌握简单ER图模型建模工具 E-R模型 Entity-Relationship Model E-R模型是一种数据建模的思想。 1. E-R模型的基本观点&#xff1a; 世…

数据库设计(1)—需求分析

2019独角兽企业重金招聘Python工程师标准>>> 需求分析是设计数据库的起点&#xff0c;需求分析结果是否准确反映用户的实际要求将直接影响到后面各阶段的设计&#xff0c;并影响到设计结果是否合理实用。 一、需求分析的任务 需求的任务是通过详细调查现实世界要处理…

SQL数据库设计(一)---需求分析与逻辑设计

今天先来介绍 数据库设计中的需求分析和逻辑设计(ER图)阶段&#xff0c;明天介绍物理设计与维护优化,数据库设计是非常有意思的:-) 数据库设计 根据系统业务的需要&#xff0c;结合我们所选用的DBMS&#xff0c;为这个业务系统构建出最优的数据存储模型。 并建立好数据库中的表…

数据库设计2————需求分析

需求分析任务 1、信息需求。明确数据库需要存储的数据&#xff0c;对这些数据将哪些梳理&#xff0c;同时还要描述数据间的联系。 2、处理需求。定义系统数据处理的操作功能&#xff0c;描述操作的优先次序。包括操作的执行频率和场合&#xff0c;操作与数据间的联系&#xff…

数据库设计(一) 需求分析

目前&#xff0c;大多数的应用系统都属于数据库应用程序&#xff0c;都离不开数据库的支持。数据库设计方案的优劣对于应用程序的运行至关重要。数据库设计过程就是针对具体的应用环境&#xff0c;设计优化的逻辑模式&#xff0c;并根据所采用的数据库系统设计物理结构&#xf…

三、数据需求与数据库设计

数据需求与数据库设计 数据需求 项目中主要包含了用户、权限&#xff08;菜单&#xff09;、角色三种类型的数据&#xff0c;各种数据包含的数据项如下&#xff1a; &#xff08;1&#xff09;用户&#xff1a;用户名、密码、生日、头像、简介、用户类型 &#xff08;2&…

SQL数据库实战需求分析→数据库设计

从这开始&#xff0c;就真正进入项目实战啦。先说点体会&#xff0c;我刚开始接触编程的时候&#xff0c;都是编写一些小东西&#xff0c;往往都是半天或者一天什么的就编完了&#xff0c;那时候根本没想过做程序之前还要有需求分析。经过快两年的学习&#xff0c;接触的都是比…

数据库性能需求分析及评估模型

数据库作为应用系统当中最重要的一块&#xff0c;也是性能测试非常关注的一块&#xff0c;根据我自己的项目经验&#xff0c;和以往对应用系统的性能需求分析和测试策略制定过程&#xff0c;总结一下如何开展数据库系统的性能需求分析&#xff0c;以及制定数据库能力评估模型。…

互联网应用开发实践:需求分析与数据库设计

在本文中将分析一个用于新生开学分配寝室的“宿舍秒杀”系统。从用户故事开始探索需求&#xff0c;进而分析得到系统的主要功能和非功能性需求。最后&#xff0c;根据需求分析设计数据库&#xff0c;数据库的设计原则是尽可能的方便之后的需求拓展和修改。 用户故事 用户故事一…

数据库应用系统的需求分析

一 需求分析的概念与意义 所谓的需求分析&#xff0c;就是对待开发系统要做什么&#xff0c;完成什么功能的全面描述 软件的一些特性使得需求的获取常常并不容易&#xff01; 比如软件功能复杂&#xff0c;需求可变性&#xff0c;软件的不可见性 二 获取需求的方法 面谈实地…

数据库设计:需求分析

设计一个性能良好的数据库系统&#xff0c;明确应用环境对系统的要求是首要的和基本的。因此&#xff0c;应该把对用户需求的收集和分析作为数据库设计的第一步。 需求分析的主要任务是通过详细调查要处理的对象&#xff0c;包括某个组织、某个部门、某个企业的业务管理等&…

数据库设计 | 需求分析

一、需求分析要干一个什么样的事情&#xff1f; 通过详细调查现实世界要处理的对象&#xff08;组织、部门、企业等&#xff09;&#xff0c; 充分了解原系统&#xff08;手工系统或计算机系统&#xff09;工作概况&#xff0c; 明确用户的各种需求&#xff0c;然后在此基础上确…

数据库设计之需求分析

需求分析简单地说就是分析用户的需求。根据分析是设计数据库的起点&#xff0c;需求分析结果是否准确反映用户的实际要求将直接影响到后面各阶段的设计&#xff0c;并影响到设计结果是否合理和实用。 1. 需求分析的任务 需求分析的任务是通过详细调查现实世界要处理的对象(组…

数据库技术-数据库需求分析、数据流概念

目录 需求分析 数据流 结构化分析案例-教材销购案例 例题讲解 每文一语 需求分析 1、需求分析的概念与意义 需求是指用户对软件的功能和性能的要求&#xff0c;就是用户希望软件能做什么事情&#xff0c;完成什么样的功能&#xff0c;达到什么性能。 需求分析是在计算机…

matlab gui 教学,新手入门教程(一)文本框和按钮的使用

matlab gui 教学&#xff0c;新手入门教程&#xff08;一&#xff09;文本框和按钮的使用 一、新建文件二、添加控件 一、新建文件 1、在MATLAB命令行中输入guide。 2、回车&#xff0c;进入GUI的界面&#xff0c;选择新建GUI–Blank GUI(Default)–浏览&#xff08;自定义存储…

零基础入门MATLAB(一篇十分钟)

目录 一、复数 二、取整函数 三、无穷量&#xff08;Inf&#xff09;和非数值量&#xff08;NaN&#xff09; 四、逻辑类型 五、字符和字符串 六、函数句柄 七、结构体 八、数组类型 九、单元数组 十、map容器类型 参考《MATLAB R2020a 完全自学一本通》 一、复数 …

matlab如何使输出结果更美观(symdisp函数——pretty函数升级版)

matlab中有些计算结果比较长&#xff0c;直接查看有些困难&#xff0c;下面介绍pretty和symdisp函数优化输出结果&#xff0c;使结果更为直观。 演示示例1 有一个计算结果如下&#xff1a; >> f1f1 y^5 (- w - y0)*y^4 1800*y^3 (1498200*w - 1800*y0)*y^2 (3600*w…

Matlab中textscan函数用法

目录 语法 说明 示例 读取浮点数 读取不同类型的数据 删除字面文本 跳过每行的其余部分 指定分隔符和空值转换 指定要视为空或注释的文本 将重复的分隔符视为一个分隔符 指定重复的转换设定符并收集数值数据 读取或跳过引用文本和数值字段 读取外语日期 读取非默…

【MATLAB学习笔记01】【快速入门】初识MATLAB的界面和编辑脚本的基础知识

打开MATLAB后&#xff0c;建议各位新手&#xff0c;先随便按下各个按键&#xff0c;熟悉下总体的页面布局&#xff0c;并且对各个按键的功能有点印象&#xff0c;这样可以更容易上手。 主要功能区&#xff08;下图用红色方框圈出来的位置&#xff09;&#xff1a; 命令行窗口…

零基础入门Matlab(一篇两个小时就能学完的入门博客)

目录 零基础入门matlab前言1.界面认识2.变量命名3.数据类型4.元胞数组和结构体5.矩阵操作6.程序结构7.基本绘图操作7.1.二维平面绘图7.2.三维立体绘图 8.图形的保存与导出9.补充 零基础入门matlab 前言 这篇文章很适合MATLAB的入门学习&#xff0c;这也是我在入门时学习的笔记…