【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,一经查实,立即删除!

相关文章

探索 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_…

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

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

头歌-机器学习 第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…

面试算法-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…

腾讯云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核…

前端代码优化--computed

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

openlayer实现webgis端绘制制图及编辑

在WebGIS端制图是指通过Web浏览器界面实现地理信息数据的可视化、编辑、分析以及地图产品的制作。这一过程通常涉及以下几个关键环节&#xff1a; **1. 前端技术栈&#xff1a; •HTML/CSS/JavaScript&#xff1a;作为Web开发的基础&#xff0c;用于构建用户界面布局、样式设…

Win11又来「重大」更新!

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了免费的人工智能中文站https://ai.weoknow.com 新建了收费的人工智能中文站ai人工智能工具 更多资源欢迎关注 Windows 11预览通道的22635.3420版本迎来了几个比较大的改进&#xff0c;主要有三个方面&#xff1a; …

一种快速移植 OpenHarmony Linux 内核的方法

移植概述 本文面向希望将 OpenHarmony 移植到三方芯片平台硬件的开发者&#xff0c;介绍一种借助三方芯片平台自带 Linux 内核的现有能力&#xff0c;快速移植 OpenHarmony 到三方芯片平台的方法。 移植到三方芯片平台的整体思路 内核态层和用户态层 为了更好的解释整个内核…

python-study-day1-(病人管理系统-带sql)

MainWindow代码 from tkinter import * from tkinter import messagebox from tkinter.ttk import Comboboxclass MianWindow(Frame):def __init__(self, masterNone):super().__init__(master, padx30, pady20)self.flag 0self.pack(expandTrue, fillBOTH)self.id StringVa…

深入OceanBase内部机制:系统架构与组件精讲

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! 目录 1️⃣OceanBase 整体架构1.1 分区1.2 分片1.3 日志流1.4 对等节点1.5 多租户 2️⃣OceanBase 架构与组件详解2.1 存储层2.2 …

Disk Drill Enterprise for Mac v5.5.1515数据恢复软件中文版

Disk Drill 是 Mac 操作系统固有的Mac数据恢复软件&#xff1a;使用 Recovery Vault 轻松保护文件免遭意外删除&#xff0c;并从 Mac 磁盘恢复丢失的数据。支持大多数存储设备&#xff0c;文件类型和文件系统。 软件下载&#xff1a;Disk Drill Enterprise for Mac v5.5.1515激…

keepalived2.2.8+drbd9+nfs高可用存储部署

目录 一.本文基于上一篇文章keepalived环境来做的&#xff0c;主机信息如下 二.为两台虚拟机准备添加一块新硬盘设备 三.安装drbd9 1.使用扩展源的rpm包来下载 2.创建资源并挂载到新增的硬盘 3.主设备升级身份 4.主备两个设备手动切换身份演示 四.安装配置nfs 五.安装…

【YOLOv8】Yolov5和Yolov8网络结构的分析与对比

目录 一 YOLOv5 二 YOLOv8 yolo通常采用backbone-neck-head的网络结构。 Backbone 主要负责从输入图像中提取高层次的语义特征,常包含多个卷积层和池化层&#xff0c;构建了一个深层次的特征提取器。Neck通常用来进一步整合与调整backbone提取的特征&#xff0c;有利于将不同…

大话设计模式——24.迭代器模式(Iterator Pattern)

简介 提供一种方法顺序访问一个聚合对象中各个元素&#xff0c;而又不暴露该对象的内部实现。&#xff08;Java中使用最多的设计模式之一&#xff09; UML图 应用场景 Java的集合对象&#xff1a;Collection、List、Map、Set等都有迭代器Java ArrayList的迭代器源码 示例 简…