函数递归与迭代

news2024/12/23 22:54:00

目录

1.递归

1.1递归的思想

1.2递归的限制条件

2.递归与迭代


1.递归

  • 函数递归是什么?

    递归是学习C语⾔函数绕不开的⼀个话题,那什么是递归呢?

    递归其实是⼀种解决问题的⽅法,在C语⾔中,递归就是函数⾃⼰调⽤⾃⼰。

写⼀个史上最简单的C语⾔递归代码:

#include <stdio.h>
int main()
{
 printf("hehe\n");
 main();//main函数中⼜调⽤了main函数 死循环不断的打印hehe
 return 0;
}
  • 每一次函数调用,都要为这次函数调用分配内存空间是内存的栈区上分配的,如果无限的递归调用函数,就会将栈区空间填满(使用完) ,这时就出现了栈溢出(Stack flow)的现象

1.1递归的思想

把⼀个⼤型复杂问题层层转化为⼀个与原问题相似,但规模较小的⼦问题来求解;直到⼦问题不能再被拆分,递归就结束了。所以递归的思考⽅式就是把⼤事化⼩的过程。

递归中的递就是递推的意思,归就是回归的意思,接下来慢慢来体会

1.2递归的限制条件

递归在书写的时候,有2个必要条件(一定要写):

  • 递归存在限制条件,当满足这个限制条件的时候,递归便不再继续。

  • 每次递归调⽤之后越来越接近这个限制条件。

在下面的例⼦中,我们逐步体会这2个限制条件

题⽬:计算n的阶乘(不考虑溢出),n的阶乘就是1~n的数字累积相乘。

当 n==0 的时候,n的阶乘是1,其余n的阶乘都是可以通过公式计算。

n的阶乘的递归公式如下:

  • 递归就是:递推,回归的意思,一开始先一步步的递推下去,然后再回归将结果一个个计算得到最终结果

  • 少量的代码完成复杂的运算(递归不断的申请内存空间如果不及时结束的话就会溢出)

int Fact(int n) {   
        if (n == 0) {  //n=0限制条件结束条件
            return 1; // n=0的时候不再往下拆解  达到限制条件
        }
        else if (n > 0)
        {
            return n * Fact(n - 1);
        }
        else
        {
            printf("输入的值有误请重新输入:\n");
        }
​
    }
int main() {
    int n = 0;
    scanf("%d", &n);
    int ret = Fact(n);
    printf("%d", ret);
    return 0;
}
  • 输⼊⼀个整数m,按照顺序打印整数的每⼀位。

  • 分析:用递归的方法 我们将 1234 按顺序输出 1 2 3 4

    我们可以定义一个Print()函数

    先递推:(一直递推到最高位,然后再从最高位开始打印,就会按顺序输出)

    (1234) 除以十去掉最后一位 (123) 4

    (123) 4 ---> (12) 3 4 ----> (1)2 3 4 ---> 1 2 3 4

    每次都调用自己,直到不能再分(限制条件)

    后回归:

  • 最后当n=1的时候不满足n>9的条件,达到限制条件然后进行回归,

    1%10 = 1

    12%10=2

    123%10 =3

    然后再顺序输出1 2 3

 

int Print(int n) {
    if (n > 9)//当n是两位数以上
    {
        Print(n / 10);
    }
    printf("%d ", n % 10);
}
int main() {
    int n = 0;
    scanf("%d", &n);
    Print(n);
    
}

总结:就是写一个限制条件,然后不断的调用自己本身(递推过程),当达到限制条件的时候停止递推,然后回归(不断返回)

2.递归与迭代

递归是⼀种很好的编程技巧,但是和很多技巧⼀样,也是可能被误⽤的,就像举例1⼀样,看到推导的公式,很容易就被写成递归的形式:

int Fact(int n)
{
 if(n==0)
    return 1;
 else
    return n*Fact(n-1)
}

Fact函数是可以产⽣正确的结果,但是在递归函数调⽤的过程中涉及⼀些运⾏时的开销。

在C语⾔中每⼀次函数调⽤,都需要为本次函数调⽤在内存的栈区,申请⼀块内存空间来保存函数调⽤期间的各种局部变量的值,这块空间被称为运⾏时堆栈,或者函数栈帧。

涵数不返回,函数对应的栈帧空间就⼀直占用,所以如果函数调用中存在递归调用的话,每⼀次递归函数调用都会开辟属于自己的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间

所以如果采⽤函数递归的⽅式完成代码,递归层次太深,就会浪费太多的栈帧空间,也可能引起栈溢出(stack overflow)的问题

  • 我们可以用另外一种更简便的方法,迭代(循环中的一种)

//循环(其中一种循环是迭代)
int Fact(int n) {
    int ret = 1; //记得从1开始 如果0的话每次相乘都为0
    int i = 0;
    for (i = 1; i <= n; i++) {
        ret *= i;
    }
    return ret;
}
int main() {
    int n = 0;
    scanf("%d", &n);
    int r = Fact(n);
    printf("%d\n", r);
    return 0;
}

我们怎么权衡递归和迭代呢?

  • 如果是一个非常复杂的问题,我们可以用简单的递归方法解决,又不会造成栈溢出就使用递归调用

  • 如果用递归方法出现很明显的缺陷,造成溢出;就是用迭代的方法

比如:求斐波那契数列,用递归的方法计算,

这个代码当计算很大的数字的时候,速度非常慢,有大量重复的计算

//求斐波拉契
int Fib(int n) {
    if (n <= 2)
        return 1;
    else
        return Fib(n - 1) + Fib(n - 2);
}
int main() {
    int n = 0;
    scanf("%d", &n);
    int r = Fib(n);
    printf("%d", r);
    return 0;
}

其实递归程序会不断的展开,在展开的过程中,我们很容易就能发现,在递归的过程中会有重复计算,而且递归层次越深,冗余计算就会越多。我们可以作业测试:

int count = 0;
​
int Fib(int n) {
    if (n == 3)
        count++;//统计第3个斐波那契数被计算的次数
    if (n <= 2)
        return 1;
    else
        return Fib(n - 1) + Fib(n - 2);
}
​
int main() {
    int n = 0;
    scanf("%d", &n);
    int r = Fib(n);
    printf("%d\n", r);
    printf("count=%d", count);
    return 0;
}

 

这⾥我们看到了,在计算第40个斐波那契数的时候,使⽤递归⽅式,第3个斐波那契数就被重复计算了39088169次,这些计算是非常冗余的。所以斐波那契数的计算,使⽤递归是⾮常不明智的,我们就得想迭代的⽅式解决。

我们知道斐波那契数的前2个数都1,然后前2个数相加就是第3个数,那么我们从前往后,从小到大计算就行了。

这样就有下⾯的代码:

//用迭代的方法
int Fib(int n) {
    int a = 1;
    int b = 1;
    int c = 1;
    while (n > 2) {
        c = a + b;
        a = b;  //将算出来的值后面两个赋值 给前两个
        b = c;
        n--;//每次剪到2的时候就退出循环
    }
    return c;
}
int main() {
    int n = 0;
    scanf("%d", &n);
    int r = Fib(n);
    printf("%d\n", r);
    return 0;
}
  • 有个递归的例子(递归层次太深),会死递归;溢出 等他一直加到3989的时候就会溢出

  • 上面斐波拉契函数递归层次不会太深,但是次数冗余

void test(int n) {
    printf("%d ", n);
    if (n <= 10000) {
        test(n + 1);  
    }
}
​
int main() {
    test(1);
    return 0;
}

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

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

相关文章

引入高德地图

1、配置 试试keytool 有没有反应 就算java -version没问题也一定是你没配path路径 在系统中配到bin就行了 2、获取密钥 网上真的坑太多了还有有chat问了一下 keytool -v -list -keystore "C:\Users\xxxx\.android\debug.keystore"执行这个你看你的 3、去高德地…

Office疑难杂症-Word页码重复无法修改

在现代办公环境中&#xff0c;Microsoft Office 套件扮演着不可或缺的角色&#xff0c;尤其是 Word 文档处理软件&#xff0c;在日常生活和工作中的应用广泛。然而&#xff0c;即使是这样成熟的软件&#xff0c;也不免有一些令人头疼的技术问题。本文将详细介绍如何解决Word中页…

【Python】常用数据结构

1、熟悉字典和列表 2、使用条件判断语句 3、list列表中计算 1、从键盘输人一个正整数列表,以-1结束,分别计算列表中奇数和偶数的和。 &#xff08;1&#xff09;源代码&#xff1a; # 初始化奇数和偶数的和为0 odd_sum 0 even_sum 0 #输入 while True:num int(input(&qu…

【InternLM】基于弱智吧数据的微调数据构造实验

1. 数据处理流程 在AI领域有句名言&#xff1a;数据和特征决定了机器学习的上限&#xff0c;而模型和算法只是逼近这个上限而已。可见数据对整个AI的决定性影响&#xff0c;在模型开源化的今天&#xff0c;很多厂商的模型结构都大同小异&#xff0c;那影响最终模型的一大决定因…

Cranck-Nicolson隐式方法解线性双曲型方程

Cranck-Nicolson隐式方法解线性双曲型方程 Cranck-Nicolson方法在抛物型方程里面比较常用&#xff0c;双曲型方程例子不多&#xff0c;该方法是二阶精度&#xff0c;无条件稳定&#xff0c;然而&#xff0c;数值震荡比较明显&#xff0c;特别是时间演化比较大以及courant数比较…

基于Spring Boot的实验室管理系统设计与实现

基于Spring Boot的实验室管理系统设计与实现 开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/idea 系统部分展示 管理员登录界面&#xff0c;管理员通过后台登录窗口进…

Maven介绍 主要包括Maven的基本介绍,作用,以及对应的Maven模型,可以对Maven有一个基本的了解

1、Maven介绍 1.1 什么是Maven Maven是Apache旗下的一个开源项目&#xff0c;是一款用于管理和构建java项目的工具。 官网&#xff1a;https://maven.apache.org/ Apache 软件基金会&#xff0c;成立于1999年7月&#xff0c;是目前世界上最大的最受欢迎的开源软件基金会&…

Visual Studio Code基础:打开一个编辑器(文件)时,覆盖了原编辑器

相关阅读 VS codehttps://blog.csdn.net/weixin_45791458/category_12658212.html?spm1001.2014.3001.5482 在使用vscode时&#xff0c;偶尔会出现这样的问题&#xff1a;打开了某个编辑器&#xff08;文件&#xff0c;下面统称文件&#xff09;后&#xff0c;再打开其他文件…

【触摸案例-控件不能响应的情况 Objective-C语言】

一、接下来,我们来说这个“控件不能响应的情况”, 1.素材里边,有一个“不接受用户交互的情况”,这么一个代码,把它打开, 把这个项目啊,复制过来,改一个名字,叫做“04-控件不能响应的情况”, 打开之后,command + R,运行一下, 在storyboard上,你也可以看得出来,我…

系统服务(22年国赛)—— nmcli命令部署VXLAN

前言&#xff1a;原文在我的博客网站中&#xff0c;持续更新数通、系统方面的知识&#xff0c;欢迎来访&#xff01; 系统服务&#xff08;22年国赛&#xff09;—— VXLAN服务部署https://myweb.myskillstree.cn/118.html 目录 题目&#xff1a; AppSrv 关闭防火墙和SEli…

哈夫曼编码---一种无损数据压缩算法

哈夫曼编码是一种无损数据压缩算法&#xff0c;该算法在数据压缩&#xff0c;存储和网络传输等领域广泛引用&#xff0c;对互联网的发展也产生了深远的影响。 大家熟知的数据无损压缩软件&#xff0c;如WinRAR&#xff0c;gzip&#xff0c;bzip&#xff0c;lzw&#xff0c;7-z…

ThreeJs 环境配置及遇到问题的解决方法

一、环境搭建 ThreeJs在实际在实际使用中更多的是结合框架开发例如&#xff1a;vue框架、react框架&#xff0c;在使用时需要配置开发环境&#xff0c;本文使用的是vscode ThreeJs NodeJs vue 1、ThreeJs安装 下载路径&#xff1a;GitHub - mrdoob/three.js: JavaScript…

如何进行制造设备数据汇集,发挥数据的价值?

数字化转型正深刻推动制造企业实现远程监控、提高生产效率、降低生产成本、优化产品质量及明晰精细化方向。并且工业互联网的发展离不开工业数据的应用&#xff0c;而制造设备数据汇集正是应用的基础。但制造设备数据汇集存在以下难点及痛点&#xff1a; 1、安全把控难 关键的…

windows日志怎么打开/查看?

windows日志里可以查看到系统进行的各种操作,包括正常开关机记录、dhcp配置警告信息等等,不过很多小伙伴并不知道怎么打开windows日志,为此为大家整理了三种快速打开windows系统日志的方法,大家有需要的话赶紧来看看吧。 目录 一、方法1 二、方法2 三、方法3 (推荐) 一…

基于SpringBoot+Vue乡村养老服务管理系统

项目介绍&#xff1a; 使用旧方法对乡村养老服务管理系统登录的信息进行系统化管理已经不再让人们信赖了&#xff0c;把现在的网络信息技术运用在乡村养老服务管理系统登录的管理上面可以解决许多信息管理上面的难题&#xff0c;比如处理数据时间很长&#xff0c;数据存在错误…

如何用Python语言实现远程控制4路控制器/断路器

如何用Python语言实现远程控制4路控制器/断路器呢&#xff1f; 本文描述了使用Python语言调用HTTP接口&#xff0c;实现控制4路控制器/断路器&#xff0c;支持4路输出&#xff0c;均可独立控制&#xff0c;可接入各种电器。 可选用产品&#xff1a;可根据实际场景需求&#xf…

网红大佬的面子,高阶智驾的里子 | 2024北京车展

相关阅读&#xff1a;2023北京车展 《没有争奇斗艳的车模&#xff0c;只有往死里卷的智能汽车》。 文&#xff5c;刘俊宏 李想、李斌绑定“车圈新顶流”雷军互相抬轿子&#xff0c;红衣大叔周鸿祎高情商点评各家汽车新品...... 为了流量&#xff0c;今年车企大佬们比任何时候…

2024李卜常识王小晨申论类比刷题课

2024年&#xff0c;李卜常识与王小晨申论类比刷题课成为备考公务员考试的热门选择。李卜老师以其深厚的学识&#xff0c;为学员们剖析常识的精髓&#xff1b;而王小晨老师则通过类比刷题的方式&#xff0c;帮助学员们掌握申论的技巧。这两门课程相互补充&#xff0c;让学员们在…

「51媒体」政企宣传邀请媒体的作用?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 政企宣传邀请媒体的作用主要体现在以下几个方面&#xff1a; 提升品牌知名度&#xff1a;通过媒体广泛报道活动内容、亮点及企业形象&#xff0c;可以提升企业或政府的品牌知名度。 增加…

kaggle(4) Regression with an Abalone Dataset 鲍鱼数据集的回归

kaggle&#xff08;4&#xff09; Regression with an Abalone Dataset 鲍鱼数据集的回归 import pandas as pd import numpy as npimport xgboost import lightgbm import optuna import catboostfrom sklearn.model_selection import train_test_split from sklearn.metrics …