当前位置: 首页 > news >正文

带你了解“函数递归”

目录

1. 什么是递归?

2. 函数递归的必要条件

2.1 接收一个整型值(无符号),按照顺序打印它的每一位。

代码如下:

2.2 编写一个函数,不用临时变量求字符串长度

代码如下:

2.3 递归与迭代

2.3.1 求n!(不考虑溢出)

代码如下:

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

代码如下


1. 什么是递归?

  • 程序调用自身的编程技巧称为i而递归(recursion)。
  • 递归作为一种算法再程序设计语言中广泛应用。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为为一个与原问题相似的规模较小的问题来求解,递归策略只需要只需要少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
  • 递归的主要思考方式在于:大事化小

现在看这个概念可能有一点抽象,我们举一个最简单的例子:

int main()
{printf("LOVE YOU\n");main();//函数在里面自己调用自己就是递归return 0;
}

但是这个代码还是有一定的问题的:它会栈溢出

内存分为栈区、堆区和静态区,我们知道当我们调用函数时,它会在栈区申请空间。但是我们这个函数是无限循环的,它一直调用main函数,直到栈区没有空间了,它才停止。

 当然,这只是一个例子,我们在写代码的时候,不会这样写。

2. 函数递归的必要条件

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

2.1 接收一个整型值(无符号),按照顺序打印它的每一位。

例如:

输入:1234,输出:1 2 3 4.

我们可以先看看能不能计算:

1234%10=4(打印)

1234/10=123

123%10=3(打印)

123/10=12

12%10=2(打印)

12/10=1

1%10=1(打印)

这样虽然可以计算,但是顺序错了,用刚刚学的递归就可以解决(我们这里的限制条件是:只剩下个位数后不需要递归)

代码如下:

#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;
}

代码可能有些难理解,我们看下面的图:

递归的递是递推,就是上面的绿色箭头

递归的归是回归,就是上面的红色箭头

2.2 编写一个函数,不用临时变量求字符串长度

乍一看这个问题好像很难,没关系,我们先减小难度。编写一个函数求字符串长度

很简单对吧,我们再加一点难度:用调用函数写

arr[10]="a b c d e f \0 _ _ _"

  1. 首先我们要知道数组 arr 的指针就是第一个字母 a 的指针
  2. 当我们的指针 str 指向 a 时,我们记为 1 ,然后 str++,指针向下走指向 b ……最后当 str = ' \0 ' 时停止计数,所以这是一个循环。
  3. 定义一个计数变量 count ,每当进入循环 count++;str++;
  4. 当循环结束,返回 count  。
#include <stdio.h>
#include <string.h>int my_strlen(char* str)
{int count = 0;while (*str != '\0'){count++;str++;}return count;
}int main()
{char arr[10] = "abcdef";int len = my_strlen(arr);printf("%d\n", len);return 0;
}

理解之后我们进一步改良,使其符合题目:

题目不需要临时变量,count就不能用了。但是,我们还是之前的思路,只是用递归的方法:

首先,递归要有一个限制条件:指针不为 ' \0 '。满足这个条件后,指针+1,但是我们还要计数,直接返回的时候+1。否则,也就是说如果一开始就是 ' \0 ' ,那我们就直接返回0。

代码如下:

#include <stdio.h>
#include <string.h>int my_strlen(char* str)
{if (*str != '\0'){return 1 + my_strlen(str + 1);}elsereturn 0;
}int main()
{char arr[10] = "abcdef";int len = my_strlen(arr);printf("%d\n", len);return 0;
}

2.3 递归与迭代

循环是迭代的一种:

  1. 循环(loop),指的是在满足条件的情况下,重复执行同一段代码。比如,while语句。 循环则技能对应集合,列表,数组等,也能对执行代码进行操作。
  2. 迭代(iterate),指的是按照某种顺序逐个访问列表中的每一项。比如,for语句。 迭代只能对应集合,列表,数组等。不能对执行代码进行迭代。

2.3.1 求n!(不考虑溢出)

我们以前也写过求 n!  :

  • 主函数:输入n,定义ret接收调用函数 fac 的返回值,打印 ret 。
  • 调用函数:定义 i=1 和 ret=1 ,循环出 1 - n 的数,让 i <= n ,不断让 ret = ret * i 。
#include <stdio.h>int fac(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", &n);int ret=fac(n);printf("%d\n", ret);return 0;
}

除了这种循环(迭代)的写法,我们还可以改良一下,用递归写:fac(n) = n * fac(n-1)

  • 当 n <= 1 时,返回1
  • 当 n > 1 时,返回 n * fac(n-1)

代码如下:

int fac(int n)
{if (n <= 1)return 1;elsereturn n * fac(n - 1);}int main()
{int n = 0;scanf("%d", &n);int ret = fac(n);printf("%d", ret);return 0;
}

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

斐波那契数列指的是这样一个数列:1,1,2,3,5,8,13,21,34,55,89...

  • 这个数列从第3项开始,每一项都等于前两项之和。
  • 在数学上,斐波那契数列以如下被以递推的方法定义:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(≥ 2,∈ N*)

要写这个函数,首先我们要知道前两个数字,第三项开始就是前两项之和,我们只需要计算到 n * (n-1) 。

当 n <= 2 ,斐波那契数是 1 ;

当 n > 2 ,斐波那契数是前两项之和;

int Fib(int n)
{if (n <= 2)return 1;elsereturn Fib(n - 1) + Fib(n-2);
}int main()
{int n = 0;scanf("%d", &n);int ret = Fib(n);printf("%d", ret);return 0;
}

虽然这种方法可行,但是过程非常繁琐,当你输入的数字较大时需要递归很多次,有很多重复大量的计算。

递归虽然可行,但是有没有其他的更简单的方法,不用递归,直接从前往后算:前两个相加等于第三个;用迭代的方式计算:

代码如下:

int Fib(int n)
{int a = 1;int b = 1;int c = 1;while (n>=3){c = a + b;a = b;b = c;n--;}return c;
}
int main()
{int n = 0;scanf("%d", &n);int ret = Fib(n);printf("%d", ret);return 0;
}
http://www.lryc.cn/news/25877.html

相关文章:

  • 网络资源面经2
  • 4年经验来面试20K的测试岗,一问三不知,我还真不如去招应届生。
  • K8S搭建NACOS集群踩坑问题
  • 怎么避免计算机SCI论文的重复率过高? - 易智编译EaseEditing
  • uni-app路由拦截
  • 如何使用固态继电器实现更高可靠性的隔离和更小的解决方案尺寸
  • 【YOLOv8/YOLOv7/YOLOv5系列算法改进NO.56】引入Contextual Transformer模块(sci期刊创新点之一)
  • 深圳大学计软《面向对象的程序设计》实验3 指针2
  • 【基于机器学习的推荐系统项目实战-2】项目介绍与技术选型
  • 对称锥规划:锥与对称锥
  • 4.基于Label studio的训练数据标注指南:情感分析任务观点词抽取、属性抽取
  • 算法拾遗二十五之暴力递归到动态规划五
  • Linux进程的创建结束类系统调用总结
  • Git分支的合并策略有哪些?Merge和Rebase有什么区别?关于Merge和Rebase的使用建议
  • 2022-2-23作业
  • 1.基于Label studio的训练数据标注指南:信息抽取(实体关系抽取)、文本分类等
  • “高退货率”标签引热议,亚马逊跨境电商是好是坏?
  • Pinia2
  • 服务器配置 | 在Windows本地打开服务器端Tensorboard结果
  • 13 nuxt3学习(新建页面 内置组件 assets 路由)
  • Linus命令记录(持续编辑版)
  • 玩转ThreadLocal
  • 亚马逊二审来袭,跨境电商传统验证算法真的靠谱吗?
  • 微信小程序|基于小程序+云开发制作一个租房小程序
  • 2.4 群辉驱动:多网口,系统网络只能识别两个网口 解决教程
  • Android正确使用资源res文件
  • 5分钟搭建第一个k8s集群
  • 【MySQL】查询操作(基础篇)
  • 工程管理系统+spring cloud 系统管理+java 系统设置+二次开发
  • MyBatisPlus Study Notes