【C语言初阶(11)】递归练习题

news2024/11/27 2:15:53

文章目录

  • 1. 打印一个整型的每一位
  • 2. 求字符串长度
  • 3. 求 n 的阶乘
  • 4. 求第 n 个斐波那契数
    • 4.1 递归算法
    • 4.2 非递归算法

1. 打印一个整型的每一位

题目内容

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

如何得到 1234 的每一位?

  1. 如果想得到 1234 的最后一位的话,只需要 1234 %10 就可以得到 4,得到 4 之后将之打印出来;
  2. 既然已经得到了 4,那么就不在需要它了,此时用 1234 / 10 = 123 就能去掉最后一位数;
  3. 重复上面两个步骤,直到 1234 只剩个位数的时候停止循环即可。

在这里插入图片描述

  • 此时已经了解了如何获取一个多位数上的每位数字,但是这个结果显然不是我们想要的正序打印,此时就该了解如何使用递归来求解了。

递归实现的解题思路

  • 通过前面我们已经知道 1234 最好拿到的是最后一位的 4,然而我们想要正序打印就必须先拿到第一位的 1,然后将之打印出来。
  • 也就是说,我们应该通过递归不停地 n / 10,直到 n 只剩第一位的 1 时结束递进开始回归。回归的过程中就可以很好的将 1234 的每一位打印出来了。

代码实现

#include <stdio.h>
void print(unsigned int n)
{
	if (n > 9)// n>9 说明 n 还有的拆
	{
		print(n / 10);
	}
	printf("%u ", n % 10);//递推结束开始回归时这条语句才能被执行
}
int main()
{
	unsigned int num = 1234;
	print(num);
	return 0;
}

在这里插入图片描述

代码分析

看到递归了吗
在这里插入图片描述

在这里插入图片描述

2. 求字符串长度

题目内容

  • 编写函数不允许创建临时变量,求字符串的长度。
  • 一般而言,像这种求字符串长度的题,创建临时变量来做的话都蛮简单的。

在这里插入图片描述

  • 但是不允许创建临时变量就显得很变态了,此时只能使用递归来写了。

解题思路

  • 数组在传参的时候传过去的是数组首元素的地址,如果这个地址指向的第一个字符不是 \0 那串的长度就至少为 1,就可以进行递归;
  • 每次递归让地址 +1 指向下一个字符,并且数量 +1 ,直到遇到 \0 递归结束,开始返回。
  • 在回归过程中将遇到的所有 1 全部加起来就是串的长度。

代码实现

#include <stdio.h>
int my_strlen(char* str)
{
	//如果第一个字符不等于 \0,那它的长度至少是1
	if (*str != '\0')
	{
		return 1 + my_strlen(str+1);
	}
	else
	{
		return 0;
	}
}
int main()
{
	char arr[] = "abc";
	printf("%d\n", my_strlen(arr));
	return 0;
}

在这里插入图片描述

代码分析

my_strlen(“abc”)
1 + my_strlen(“bc”)
1+1+my_strlen(“c”)
1+1+1+my_strlen(“”)

图解1
在这里插入图片描述

3. 求 n 的阶乘

阶乘公式

在这里插入图片描述

  • 有了公式的话就很好解决了,递归套用公式就行了。

代码实现

#include <stdio.h>
int fac(int n)
{
	if (n > 1)
	{
		return n * fac(n - 1);
	}
	else
	{
		return 1;// 0 和 1 的阶乘都是 1
	}
}
int main()
{
	int n;
	scanf("%d", &n);//以 n =  5 做例子
	printf("%d\n", fac(n));
	return 0;
}

在这里插入图片描述

代码分析

在这里插入图片描述
在这里插入图片描述

4. 求第 n 个斐波那契数

斐波那契数

  • 斐波那契数列指的是这样一个数列:
    • 1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711……
  • 它们的规律是:这个数列从第 3 项开始,每一项都等于前两项之和。

4.1 递归算法

斐波那契数公式

  • 通过求阶乘那节可以发现,在有了函数公式的情况下,递归写起来基本就是有手就行了;
  • 斐波那契数当然也有自己的公式:

在这里插入图片描述

代码实现

#include <stdio.h>
int Fib(int n)
{
	if (n > 2) //从第三位才开始求斐波那契数
	{
		return Fib(n - 1) + Fib(n - 2);
		//公式:fib(n) = fib(n-1) + fib(n-2)
	}
	else
	{
		return 1; // 前两个斐波那契数都是 1
	}
}
int main()
{
	int n;
	scanf("%d", &n);
	printf("%d\n", Fib(n));
	return 0;
}

在这里插入图片描述

  • 在使用 fib 这个函数的时候如果我们要计算第 50 个斐波那契数字的时候特别耗费时间。
    • 博主的电脑在求第 50 个斐波那契数的时候用了有足足两分钟。

不推荐使用递归求斐波那契数

  • 在使用递归求解斐波那契数的时候,会出现大量重复性的计算,导致程序执行效率很底。
  • 如下图:想求第 6 个斐波那契数就得先求出第 5 个以及第 4 个斐波那契数;
  • 想求出第 5 个斐波那契数就又要先求 第 4 个以及第 3 个斐波那契数,这才第二步就开始出现重复运算了。

在这里插入图片描述

  • 来看看在求第 40 个斐波那契数的过程中,重复求了第 3 个斐波那契数多少次:
#include <stdio.h>
int count_fib_3 = 0;
int Fib(int n)
{
	//记录在运算某个数的过程中求了多少次第 3 个斐波那契数
	if(3==n)
	{	
		count_fib_3++;
	}
	if (n > 2)
	{
		return Fib(n - 1) + Fib(n - 2);
	}
	else
	{
		return 1;
	}
}
int main()
{
	int n;
	scanf("%d", &n);
	printf("%d\n", Fib(n));
	printf("%d\n", count_fib_3);
	return 0;
}

可以看到,光是第 3 个斐波那契数就重复求了将近四千万次,那是相当的夸张。
在这里插入图片描述

4.2 非递归算法

  • 为了解决用递归求斐波那契数出现的大量的重复计算现象,使用迭代求斐波那契数无疑是一个更好的选择。

迭代定义

  • 迭代就是重复的意思;
  • 循环是迭代,迭代不一定是循环。

解题思路

  • 使用递归我们是从后往前算的,那么使用迭代我们就从前往后算。
  • 使用三个变量来存储 第 1、2 个数以及前两数之和。
  • 通过不断交换三个变量的值,从而在一条斐波那契数列上进行移动。

解题步骤

  1. 先将变量 a 和 b 的值都赋成 1,然后执行 a + b = c ;
    • 从第 3 个数开始才去求斐波那契数,因为前两个斐波那契数都是 1。
  2. 算好之后将 b 的值赋给 a,将 c 的值赋给 b,然后执行 a + b = c,产生新的变量 a b c,然后将 n 的值减 1;
  3. 重复上面两个步骤,直到 n 的值等于 3 结束循环。

代码实现

#include <stdio.h>
int Fib(int n)
{
	int a = 1, b = 1, c = 1;
	while(n >= 3)
	{
		c = a + b;
		a = b;
		b = c;
		n--;
	}
	return c;
}
int main()
{
	int n;
	scanf("%d", &n);
	printf("%d\n", Fib(n));
	return 0;
}
  • 现在算第 50 个斐波那契数虽然结果是错的,但是效率提升上来了。

在这里插入图片描述

  • 使用了迭代的方法计算斐波那契数之后,需要重复计算的步骤就彻底被干掉了。

在这里插入图片描述

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

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

相关文章

UART串口收发数据

uart4.h ubuntuubuntu:05_uart$ cat include/uart4.h #ifndef __UART_H__ #define __UART_H__//初始化相关操作 void hal_uart4_init();//发送一个字符 void hal_put_char(const char str);//发送一个字符串 void hal_put_string(const char* string);//接收一个字符 char h…

中医_治方

&#x1f368;中医治方 &#x1f354;普通&#x1f333;肺之实症&#x1f333;过食瓜果&#x1f333;补气&#x1f333;五脏逼毒法&#x1f333;判断是否有儿子&#x1f333;酒糟鼻&#x1f333;判断处女&#x1f333; 判断下一胎性别&#x1f333; 头痛&#x1f333; 音哑发不…

AI绘画结合GPT 把Ai绘画与摄影玩明白

一、绘画与摄影有什么关系&#xff1f; 绘画和摄影是两种不同的艺术形式&#xff0c;它们都以其自身独特的方式捕捉和表达现实。在某些方面&#xff0c;它们是相互联系的&#xff0c;而在其他方面&#xff0c;它们又有所不同。​ 相似之处&#xff1a;绘画和摄影都是创造性的…

Docker网络管理应用

实验要求 了解Docker常用网络模式&#xff0c;掌握Docker常用网络模式的使用。主要任务是利用busybox镜像建立容器&#xff0c;容器名称为test_busybox1和test_busybox2&#xff0c;将网络模式设置为none&#xff0c;并为容器配置IP地址&#xff0c;容器test_busybox1的IP设置…

21-部署 Web 项目到 Linux

目录 1.什么是部署&#xff1f; 2.如何部署&#xff1f; 2.1.本机连接远程mysql服务器&#xff08;可选项&#xff09; 2.2.在远程服务器mysql数据库上执行创建数据库、表的脚本 2.3.检查项目中连接mysql服务器的地址和密码是否正确 2.4.使用Maven打包项目&#xff0c;生…

Linux组件之内存池的实现

文章目录 一、为什么需要内存池二、内存池的工作流程三、内存池的实现3.1 数据结构3.2 接口设计3.2.1 创建内存池3.2.2 内存池销毁3.2.3 内存分配1. 分配小块内存2. 分配大块内存 3.2.4 内存池的释放3.2.5 内存池重置 3.3 完整代码 一、为什么需要内存池 应用程序使用内存&…

ArcPy学习心得系列(6)Arcpy计算DOM影像数据范围

需求分析 DOM影像有黑边怎么办? 下图为DOM影像 一张DOM图,问有没有方法能够计算出这张图的有效数据的范围 通过图中显示的范围,可以很明显的看到左边多出来的那一块区域,仔细排查了一遍,辉仔发现原始数据实际上是下面这样的。 原始DOM影像 其中,蓝色区域的值为255,…

Django中如何正确使用 redis

文章目录 问题起源&#xff1a;AsyncWebsocketConsumer 中的 channel_layer解决方案安装 & 启动 redis安装 channel-redis更新 settings.py 的 redis 设置 问题起源&#xff1a;AsyncWebsocketConsumer 中的 channel_layer 在构建 websocket 的过程中&#xff0c;我在 cons…

云原生之深入解析K8S的请求和限制

一、Kubernetes 限制和请求 在 Kubernetes 中使用容器时&#xff0c;了解涉及的资源是什么以及为何需要它们很重要。有些进程比其它进程需要更多的 CPU 或内存&#xff0c;这很关键&#xff0c;永远不应该让进程饥饿&#xff0c;知道了这一点&#xff0c;那么应该正确配置容器…

MQTT 5.0 中的安全认证机制:增强认证介绍

在本系列之前的文章中我们提到&#xff0c;借助 MQTT CONNECT 报文中的 Username 和 Password 字段&#xff0c;我们可以实现一些简单的认证&#xff0c;比如密码认证、Token 认证等。为了进一步保障物联网系统的安全&#xff0c;在本期文章中&#xff0c;我们将一起了解另一种…

tty(四)tty框架分析

基于linux-3.14.16 重要文件&#xff1a;tty_io.c 一、tty子系统 开机添加了2个次设备号为0和1的字符设备&#xff0c;即/dev/tty和/dev/console。 二、分配tty驱动接口alloc_tty_driver 最终调用的__tty_alloc_driver分配 先分配一个tty_driver 因为flags为0&#xff0c…

从编程开发角度比较电机驱动芯片:DRV8833、TB6612、A4950、L298N

这几款驱动芯片都是用于控制直流电机的常见驱动芯片&#xff0c;下面是它们的相同点和不同点的比较&#xff1a; 相同点&#xff1a; 都可以用于控制直流电机的转速和方向。 都支持PWM控制方式&#xff0c;可以实现电机的速度调节。 都提供了使能引脚&#xff0c;可以通过使…

(ARM)7/5

1.串口发送单个字符 2.串口发送字符串 uart4.h #ifndef __UART4_H__ #define __UART4_H__#include "stm32mp1xx_uart.h" #include "stm32mp1xx_rcc.h" #include "stm32mp1xx_gpio.h"//初始化相关操作 void hal_uart4_init();//发送一个字符 v…

uniapp学习之【uniapp的返回事件 onBackPress 在微信小程序中不生效的问题】

uniapp 的返回事件 onBackPress 在微信小程序中不生效的问题 场景&#xff1a;页面中点击左上角的返回按钮,监听返回操作,页面返回前执行了一些操作, uniapp 页面生命周期中有 onBackPress ,因此将操作写在了 onBackPress () 页面生命周期钩子当中, H5 测试一切正常,但是微信开…

7、架构:模板设计

在低代码开发中&#xff0c;除了基础组件与物料之外&#xff0c;模板也是必不可少的模块&#xff0c;是基于物料之上的更高级的产物&#xff0c;除了具备业务属性之外会更偏向专属的技术领域&#xff0c;例如可视化大屏、数据分析、中台管理等。 此外模板通常是比较完整的应用…

k8s Label 2

在 k8s 中&#xff0c;我们会轻轻松松的部署几十上百个微服务&#xff0c;这些微服务的版本&#xff0c;副本数的不同进而会带出更多的 pod 这么多的 pod &#xff0c;如何才能高效的将他们组织起来的&#xff0c;如果组织不好便会让管理微服务变得混乱不堪&#xff0c;杂乱无…

作物计数方法汇总

在研究农情的方向中&#xff0c;作物计数是一个很重要的方向&#xff0c;需要用到很多方法&#xff0c;这里做一个小小的总结 (1)地理栅格数据(tif图片)裁剪并生成带地理坐标的切片 如图需要将下图所示的tif图裁剪并生成切片&#xff08;截图一部分&#xff09; 源码来自&…

微服务 02-rabbitmq在springboot中如何使用(上篇)

目录 前言: 上文传送 -> 安装rabbitmq传送门: -> rabbitmq使用出现问题解决传送门: 1. rabbitmq的六大模式: 1.1 简单模式: (一对一) -> 业务场景: 1.2 工作模式: (一对多) -> 业务场景: 1.3 发布与订阅模式: (广播) 1.4 路由模式: -> 业务场景 …

计算机系统的层次结构

计算机系统 计 算 机 系 统 { 计 算 机 软 件 { 系 统 软 件 应 用 软 件 计 算 机 硬 件 { 存 储 器 运 算 器 控 制 器 输 入 设 备 输 出 设 备 计算机系统 \begin{cases} 计算机软件\begin{cases}系统软件\\应用软件\end{cases}\\计算机硬件\begin{cases}存储器\\运算器\…

YoloV8改进---注意力机制:引入瓶颈注意力模块BAM,对标CBAM

目录 ​编辑 1.BAM介绍 2.BAM引入到yolov8 2.1 加入modules.py中&#xff1a; 2.2 加入tasks.py中&#xff1a; 2.3 yolov8_BAM.yaml 1.BAM介绍 论文&#xff1a;https://arxiv.org/pdf/1807.06514.pdf 摘要&#xff1a;提出了一种简单有效的注意力模块&#xff0c;称为瓶颈…