【C语言】函数递归编程题

目录

题目一:

题目二:

题目三:

题目四:

总结


题目一:

题目:接受一个整型值(无符号),按照顺序打印它的每一位。(递归完成)

列如:

输入:1234,输出1 2 3 4

题目解析:

  • 接受一个整型值(无符号),那就是输入的数不能为负数
  • 持续获得整数的个位值,方法为:n % 10得到个位,n / 10 得到除了个位以外的数
  • 重复n%10,n/10,n%10.....直到n%10 = n,就把一个整数拆分了
  • 需要按照顺序打印,这里使用递归是比较合适的
  • 我们使用大事化小的方式思考,当n<=9的时候,表示这个整数只剩下/只有个位,那就说明该整数为n本身
  • 当n>9的时候,可以将整数1234拆分为,123和4,因为4是很容易得到的,对1234%10=4,那我们让123先打印在屏幕上,然后再打印4
  • 以此类推,123拆分为12和3,12拆分为1和2,当想再拆分1时,发现1<=9,则只剩个位,然后将1本身进行打印,再往前进行打印
  • 下面是图解:

代码实现:

//接受一个整型值(无符号),按照顺序打印它的每一位。
//例如:输入:1234,输出 1 2 3 4.
void Print(unsigned int n)
{//n>9表示n不止1位数if (n > 9)// n/10 --> 得到除个位的其它数Print(n / 10);//当n<=9时,说明此时n只有一位数,进行n%10=nprintf("%d ", n % 10);
}
int main()
{//unsigned int 表示无符号整型unsigned int num = 0;scanf("%u", &num); //%u为无符号整形的格式化字符Print(num); //用于按照顺序打印每一位数return 0;
}

对代码进行图解:


题目二:

题目:编写函数不允许创建临时变量,求字符串的长度。(递归/迭代)

题解:

  • 求字符串的长度,在C语言中有一个库函数strlen,题目要求编写函数,那就是说让我们模拟实现strlen库函数了,我们先从简单方式开始,用迭代的方式模拟实现strlen,并且允许创建临时变量:
//使用临时变量,迭代方式模拟实现strlen
#include <string.h>
int Strlen(char* parr)
{int count = 0;while (*parr != '\0'){count++;parr++;}return count;
}
int main()
{char arr[10] = "abcdef";int n = Strlen(arr);printf("%d\n", n);return 0;
}
  • 按照这个思路,我们想想如何不使用临时变量,迭代方式模拟实现strlen呢?其实可以利用指针的计算特性 ,创建一个指向parr的指针,该指针不算临时变量,然后让该指针进行遍历,直到指向'\0',然后利用指针计算特性:尾地址 - 首地址 = 元素个数。(因为地字符串地址中的每个字符地址是连续的)
//不使用临时变量,迭代方式模拟实现strlen
#include <string.h>
int Strlen(char* parr)
{char* tmp = parr;while (*tmp != '\0'){tmp++;}return tmp - parr;
}
int main()
{char arr[10] = "abcdef";int n = Strlen(arr);printf("%d\n", n);return 0;
}
  • 利用递归模拟实现strlen就得转变一下思路了,使用大事化小思想,当是空字符时,字符个数为0,当*parr!='\0'则最少有一个字符时,字符个数>0,那我们可以把字符串看成一个整体,进行拆分,一个字符+ (n-1)个字符,一直拆,一个字符 + (n-2)个字符.....,直到变为空字符,再从0开始往回相加,具体看代码:
//不使用临时变量,递归方式模拟实现strlen
#include <string.h>
int Strlen(char* parr)
{while (*parr != '\0'){//!='\0'时最少1个字符return 1 + Strlen(parr + 1); //parr+1 表示拿到下一个字符的地址}return 0; //当为空字符时
}
int main()
{char arr[10] = "abcdef";int n = Strlen(arr);printf("%d\n", n);return 0;
}

注意:

  • 不要写出parr++,因为这是后置++,是先将地址传过去了,才进行+1操作,这就不符合存在限制条件,当满足这个限制条件的时候,递归便不再继续这个条件了。
  • 每递归一次,都会创建一个临时指针变量str,因此parr++操作,先把原本的地址传递过去了,然后自己在+1,指向下一个字符,但并没有影响到其它的parr,parr+1也只存在于调用前那块parr空间,因此程序陷入死循环,直到栈溢出。
  • 因此,在递归时,尽量不要写前置++与后置++,因为会把parr指针的指向改变。修改本身,建议parr+ 1,这种不会修改本身,只是得到当前指向的下一个地址。

代码图解:


题目三:

题目:求n的阶乘。(不考虑溢出)

题解:

  • 用递归求n的阶乘,当n为<2时,阶乘为1,当n>=2时,可以看出n * (n-1)个阶乘,因为一个阶乘往往是从1乘到n,因此可以进行拆分,直到n<2,拆分不了了,开始返回相乘。(从后往前乘)
  • 因此得出公式:

  • 代码如下:
//递归求n的阶乘
int factorial(int n)
{if (n>=2){return n * factorial(n-1);}return 1;
}
int main()
{int n = 0;scanf("%d", &n);int sum = factorial(n);printf("%d\n", sum);return 0;
}

当然,使用 factorial 函数求10000的阶乘(不考虑结果的正确性),程序会崩溃。因为栈区的空间是有上限的,超过了就会导致栈溢出。对于这种情况,最好的解决办法就是将递归改写成非递归:

//迭代求n的阶乘
int factorial(int n)
{int res = 1;for (int i = 1; i <= n; i++){res *= i;}return res;
}
int main()
{int n = 0;scanf("%d", &n);int sum = factorial(n);printf("%d\n", sum);return 0;
}

当然了,结果肯定是不对的,这里解决的只是防止栈溢出的情况,要想结果正确,需要分配内存更大的类型,因为res 为整型,当数值太大,整型存储不下,就会溢出。


题目四:

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

题解:

  • 斐波那契数为:前两个数相加 = 当前数
  • 要使用递归进行求解,那么需要考虑限定条件,当求n<3时,斐波那契数均为1,因为想形成斐波那契数,最少需要3个数。
  • 然后我们思考n>2的情况,(第n-1个斐波那契数)+(第n-2个斐波那契数),递归,直到n<3,返回1
  • 代码如下:
//求第n个斐波那契数(递归实现)
int fibonacci(int n)
{if (n>2){return fibonacci(n - 1) + fibonacci(n - 2);}return 1;
}
int main()
{int n = 0;scanf("%d", &n);int fibonacci_number = fibonacci(n);printf("%d\n", fibonacci_number);return 0;
}

代码图解:

但是我们发现有问题:在使用这个函数的时候如果我们要计算第50个斐波那契数字的时候特别耗费时间。为什么呢?我们可以记一下数:

int count = 0;//全局变量
int fibonacci(int n)
{//统计整个递归下来,求第3个斐波那契数会执行多少次if (n == 3){count++;}if (n>2)return fibonacci(n - 1) + fibonacci(n - 2);return 1;
}
int main()
{int n = 0;scanf("%d", &n);int fibonacci_number = fibonacci(n);printf("%d\n", fibonacci_number);return 0;
}

当计算第40个斐波那契数时,n == 3的执行次数已经很大了,我们看看下面这张图:

我们发现会有很多重复的次数被重复计算,因为我们是从后往前计算的,看公式:Fb(n-1) + Fb(n-2) 这种计算方式会有很多重复的计算,比如算第10个斐波那契数:

有很多重复的计算。那如何解决呢?其实我们可以使用迭代的方式进行计算:(从前往后算),还是求第10个斐波那契数:

代码如下:

//迭代求第n个斐波那契数
int fibonacci(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 fibonacci_number = fibonacci(n);printf("%d\n", fibonacci_number);return 0;
}

图解如下:

关于求解第n个斐波那契数的总结图:


题目五:

题目名称:
计算一个数的每位之和(递归实现)
题目内容:
写一个递归函数DigitSum(n),输入一个非负整数,返回组成它的数字之和
例如,调用DigitSum(1729),则应该返回1+7+2+9,它的和是19
输入:1729,输出:19

题解:

  • 关注点应该在k次方上,当k为1次方时,无论n是什么数,结果都为1
  • 我们可以进行拆分,n^k --> n*n^k-1
  • 相当于n^1 * n^k-1,不断拆分下去,直到k<2,返回
  • 注意点:如果n == 1,那返回1
  • 看代码:
int Com_n_K(int n,int k)
{//当次方数<2时,结果为n本身if (k < 2){return n;}//当n==1时,k次方结果均为1if (n == 1){return 1;}//当次方>=2时,进行拆分,n^1 * n^k-1,持续拆分,直到k<2返回nif (k>=2){return Com_n_K(n, k - 1) * n;}}
int main()
{int n = 0;int k = 0;scanf("%d %d", &n,&k);printf("%d的%d次方是:%d\n", n,k, Com_n_K(n,k));return 0;
}

代码图解:


题目六:

题目名称:
计算一个数的每位之和(递归实现)
题目内容:
写一个递归函数DigitSum(n),输入一个非负整数,返回组成它的数字之和
例如,调用DigitSum(1729),则应该返回1+7+2+9,它的和是19
输入:1729,输出:19

题解:

  • 当这个数的位数为个位时(小于10),那和为本身。
  • 列如这个数为1729,当这个数大于9时,那我们可以将这个数拆分成,172 + 9,计算172每一位之和再+9,如何将位数分离开来呢?
  • 1729%10 == 9,1729/10 = 172,按照这种规律,持续拆分下去,直到这个数只剩个位(小于10),开始回归。
  • 看代码:
int Sum_Mw(int n)
{//当n>9时,将n看成两部分,先计算除最后一位数的//每位之和,再加上最后一位数,持续拆分,直到n<10,回归n本身if (n>9){return Sum_Mw(n / 10) + n % 10;}return n;
}
int main()
{int n = 0;scanf("%d", &n);int sum = Sum_Mw(n);printf("%d\n", sum);return 0;
}

代码图解:


题目七:

题目:字符串逆序(递归实现)

题目内容:

编写一个函数 reverse_string(char * string)(递归实现)

实现:将参数字符串中的字符反向排列,不是逆序打印。

要求:不能使用C函数库中的字符串操作函数。

比如: char arr[] = "abcdef";

逆序之后数组的内容变成:fedcba

题解:

  • 既然要递归实现,那我们首先考虑递归的限制条件是什么
  • 限制条件为字符串的长度<=1时,递归结束,因为当字符串长度<=1时,可能是空字符串或者字符串中只有1个字符,这时进行返回即可,不需要进行逆序了。
  • 当字符串长度>1时,可以进行逆序操作。
  • 先模拟实现一个strlen函数,用来计算字符串的长度。
  • 然后创建一个临时变量存放头部字符,再进行与尾字符交换,这里与普通的交换不同,当最后一个字符的内容交换到头部字符后,下一步本该是将头部字符交换到末尾字符,但这里是先将末尾字符赋值成\0,而本该是末尾位置的字符存放在tmp临时变量中。
  • 为什么要先将末尾字符设置为\0呢,这是因为题目给出的函数只有一个参数,那就说明不能同时将头尾指针进行++,--操作了,那就先将头部字符暂时存储起来,让末尾字符变为\0,其实这步操作也相当于将尾指针--了,因为下一次操作时,末尾最后一个元素为前一个字符。
  • 解释清楚后,其实就是头指针++,尾指针--操作了,跟迭代思路一样,不断的循环,递归是不断的递归++,--。
  • 不断递归,当计算到字符串长度<=1时,就开始回归了。
  • 每回归一次后,将临时变量中的头部字符放置到末尾字符上,也就是之前设置成的\0位置。
  • 详细看代码:
//计算字符串长度, == strlen库函数
int Strlen_Ty(char* arr)
{int count = 0;char* Tmp_Arr = arr;while (*Tmp_Arr != '\0'){count += 1;Tmp_Arr += 1;}return count;
}
void reverse_string(char* string)
{//用于计算字符串长度的自定义函数int len = Strlen_Ty(string);//当字符串长度>1时if (len > 1){char tmp = *string;*string = *(string + len - 1);//将末尾字符,设置为\0,相当于让right--*(string + len - 1) = '\0';//递归//这里让string+1,相当于left+1reverse_string(string+1);//当递归结束,开始回归时,将尾指针修改为存在临时变量的头指针值*(string + len - 1) = tmp;}//当字符串长度<=1时,开始回归//情况1:只剩1个字符没逆序,而1个字符不需要逆序//情况2:空字符return;
}
int main()
{char arr[] = "abcdef";reverse_string(arr);printf("%s\n", arr);return 0;
}

代码图解:


总结

介绍完毕,希望能帮助到大家,后续还会出更多干货,关注我吧!!❤❤❤

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/807760.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024.3.30力扣每日一题——需要添加的硬币的最小数量

2024.3.30 题目来源我的题解方法一 数学贪心 题目来源 力扣每日一题&#xff1b;题序&#xff1a;2952 我的题解 方法一 数学贪心 首先将数组 coins按升序排序&#xff0c;然后计算需要添加的硬币的最小数量。 关键&#xff1a;对于正整数 x&#xff0c;如果区间 [1,x−1] 内…

Vue3入门大全(持续更新)

什么是Vue3 Vue.js 是一款流行的 JavaScript 前端框架&#xff0c;用于构建交互式的 Web 用户界面。Vue 3 是 Vue.js 的下一个主要版本&#xff0c;是对 Vue 2 的重大更新。Vue 3 在性能、开发体验和扩展性等方面都进行了改进和优化&#xff0c;其中一些重要的变化和功能包括&…

通过 CLI 和引入的方式使用 React:基础入门

使用React 有两种使用方式&#xff0c;主要有以下几个原因: 灵活性和适应性: 引入的方式可以让开发者在现有的 HTML 页面中快速引入 React,无需设置完整的项目环境。这适合小型或原型项目。 CLI 方式则更适合用于构建大型复杂的 React 应用程序,因为它提供了更完整的项目结构和…

探索 ChatGPT:解读 AI 对话的魔力(文末推荐一款AI工具聚合平台,可免费体验)

&#x1f947;作者简介&#xff1a;CSDN内容合伙人、新星计划第三季Python赛道Top1 &#x1f525;个人主页&#xff1a;hacker707的csdn博客 &#x1f4ac;推荐一款AI工具聚合平台&#x1f449;Hulu AI 探索 ChatGPT&#xff1a;解读 AI 对话的魔力 ChatGPT 的魅力如何使用 C…

JVM修炼之路【10】- 垃圾回收器和垃圾回收算法

垃圾回收算法 我们先简要看一下 四种主要的垃圾回收算法 看到这不禁感慨一下 人家1960年 都搞出GC算法了 太强了 评价标准 既然有这么多算法 那就跟各个牌子的游戏本一样 有个比较&#xff0c;这里我们重点介绍一下 垃圾回收算法的评价标准 这几个标准非常重要是 是后面理解很…

springCloudAlibaba集成sentinel实战(超详细)

一、Sentinel介绍 1. 什么是Sentinel Sentinel是阿里开源的项目&#xff0c;提供了流量控制、熔断降级、系统负载保护等多个维度来保障服务之间的稳定性。 分布式系统的流量防卫兵&#xff1a; 随着微服务的普及&#xff0c;服务调用的稳定性变得越来越重要。Sentinel以“流…

你知道 Java 线程池的原理吗?

Java线程池是用于管理和复用线程的机制&#xff0c;它可以帮助开发者有效地管理线程的生命周期和资源&#xff0c;并提高应用程序的性能和稳定性。 1. 线程池概述 在计算机科学中&#xff0c;线程池是一种可用来执行异步任务的线程队列。它主要包含以下几个组成部分&#xff…

python连接mysql数据库并将dataframe的数据插入表中

代码中连接的sql表为"20230411_hangzhuanlie"&#xff0c;表结构如下&#xff1a; 代码如下&#xff08;按需修改用户名、库名等即可&#xff09;&#xff1a; import pymysql import pandas as pd from sqlalchemy import create_enginehost 127.0.0.1:3306/ user_…

科研学习|论文解读——基于旅游知识图谱的游客偏好挖掘和决策支持(IPM,2023)

原文题目 Mining tourist preferences and decision support via tourism-oriented knowledge graph 摘要 目前,旅游管理研究的重点是通过对异构用户生成的内容进行广泛分析,来理解旅游偏好的波动,制定有针对性的发展策略。然而,鉴于在线景点评论涉及过多的混合和无形维度…

【51单片机入门记录】IIC总线协议 EEPROM存储器AT24C02应用

目录 一、AT24C20相关函数操作流程 &#xff08;0&#xff09;根据第十五届蓝桥杯初始iic.c进行的初步修改&#xff08;便于编写后续函数&#xff09; &#xff08;1&#xff09;AT24C20存数据操作流程及代码 &#xff08;2&#xff09;AT24C02读数据操作流程及代码 &#…

一、OpenMIPS指令集CPU的ori指令的实现

前言 根据“自己动手写CPU”这本书学习&#xff0c;自己动手实现一个MIPS指令集的CPU。 本文章实现了一个ori指令即“或”操作的五级流水线&#xff0c;后续会持续添加其他指令完善此CPU。 文章作为学习笔记持续更新&#xff0c;源代码也在github上持续更新 项目源码https://…

MySQL 行锁和表锁是什么?区别,作用等学习总结

一、所谓‘锁’ 是什么 个人理解&#xff0c;所谓的锁就是为了保证数据库数据操作的一致性而产生的一种机制&#xff0c;即我们可能有很多数据&#xff0c;但是当我们有多个人或者多个线程或会话对同一条数据或同一批数据执行操作时&#xff0c;可能大家都要修改这一部分数据&…

头歌-机器学习 第1次实验 Python机器学习软件包Scikit-Learn的学习与运用

第1关&#xff1a;使用scikit-learn导入数据集 scikit-learn包括一些标准数据集&#xff0c;不需要从外部下载&#xff0c;可直接导入使用&#xff0c;比如与分类问题相关的Iris数据集和digits手写图像数据集&#xff0c;与回归问题相关的波士顿房价数据集。 以下列举一些简单…

JAVA面试八股文之数据库

MySQL面试题 MySQL 存储引擎架构了解吗&#xff1f;CHAR 和 VARCHAR 的区别是什么&#xff1f;索引是越多越好嘛&#xff1f;MySQL数据库中空值&#xff08;null&#xff09;和空字符串&#xff08;&#xff09;的区别&#xff1f;SQL 中 on 条件与 where 条件的区别&#xff1…

mySql数据库学习003-多表查询

多表查询 创建数据表&#xff1a;班级表与学生表 create table if not exists class(id tinyint unsigned primary key auto_increment,name varchar(20) not null,description varchar(255),createAt timestamp default current_timestamp,updateAt timestamp default curre…

面试算法-171-翻转二叉树

题目 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1] 解 class Solution {public TreeNode invertTree(TreeNode root) {if (root n…

Leetcode【双指针法】

目录 一、left right在一个循环里 二、两个指针在各自的循环里 三、slow fast追逐型 四、slow fast条件型 双指针法常用与题型&#xff1a;数组、字符串、链表、N数之和 一、left right在一个循环里 left right在一个循环里。 left和right移动需要条件&#xff0c;一般是向…

腾讯云4核8G服务器多少钱?4核8G能干啥?

腾讯云4核8G服务器多少钱&#xff1f;腾讯云4核8G轻量应用服务器12M带宽租用价格646元15个月&#xff0c;活动页面 txybk.com/go/txy 活动链接打开如下图所示&#xff1a; 腾讯云4核8G服务器优惠价格 这台4核8G服务器是轻量应用服务器&#xff0c;详细配置为&#xff1a;轻量4核…

【2024年5月备考新增】冲刺(1)《第四版教材十五矩阵》

所谓十五矩阵,就是十大管理,五大过程组 【高项】信息系统项目管理师教程(第4版)十五矩阵知识领域项目管理过程组启动过程组规划过程组执行过程组监控过程组收尾过程组项目整合管理制定项目章程制订项目管理计划指导与管理项目工作监控项目工作结束项目或阶段管理项目知识实…

前端代码优化--computed

随便记录一下 主要是通过计算属性来简化和优化代码。在 Vue 中&#xff0c;计算属性是一种方便的工具&#xff0c;可以让你根据依赖状态的变化来动态计算衍生值。在这个例子中&#xff0c;我们使用计算属性 formattedCommunicationType 来根据 workDetail.realTimeItemDeviceDT…