0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

函数与递归-3

汽车电子技术 来源:微亮笔记 作者:PASSION 2023-02-21 15:57 次阅读

本期是我们函数部分的最后一节,其实我们在上两节已将函数的大致内容介绍完毕了,本节我们主要来介绍递归的知识。由于本节知识点较少,而需要大家动手操作的地方较多,我们主要以举例子的方式来介绍,接下来我们开始本期的学习。

本期我们主要学习函数递归相关的知识

  • 函数递归

什么是递归?

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

递归的两个必要条件

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

2.每次递归调用之后逐渐接近此限制条件。

所有函数递归都需要满足上述两个条件,否则函数就会出现问题,例如下面的程序:

int main()
{
  printf("hehe\\n");
  main ();//调用自身————递归
  return 0;
}

如果我们写出了这样的递归后去运行,我们就会发现程序报错,且有关键词**“stack overflow”**,这就是递归常见的错误 **“栈溢出” ** 。这里简单地介绍一下什么是栈溢出。

我们在执行程序时需要向内存申请空间,空间主要被分成三部分:栈区,堆区,静态区。在函数调用时是从栈区申请空间的,上述代码由于“main”函数重复调用自身而没有结束限制条件,违背了上面提到的递归的两个条件,导致栈区空间被使用完,造成栈溢出。

用最通俗的话来说,如果我们前面讲过的函数嵌套是一个函数调用另一个函数的话,那么函数递归就是函数通过自身调用来实现程序,下面我为大家举几个递归相关的例子

**例一:

【 接收一个整型值,按照顺序打印它的每一位。】

** 例如:输入1234,打印出1 2 3 4

#include 
void print(int n)//函数只是执行操作,不需要有返回值,所以返回值类型是“void”
{
  if(n>9)
  {
    print(n/10);//递归的具体实现
  }
  printf("%d ",n%10);
}
int main ()
{ 
  int a=0;
  scanf_s("%d",&a);
  print(a);//调用该函数
  return 0;
}
如此我们就成功地完成了任务,上述代码“print”通过不断调用自身来完成了打印整型值的任务,那我们看一下此递归是否满足了我们上面提到的两个必要条件,只要“n<9”,函数便不再递归,明显满足限制条件。

我们接下来再看一个例子:

**例二:

【 在不创建临时变量的情况下编写一个函数求一字符串的长度。】**

这道题可能刚入手有些发懵,我们先看一下在创建临时变量是如何求字符串长度的:
#include 
int strlen(char* str)
{
  int count=0;//临时变量
  while(*str != '\\0')
  {
    count++;
    str++;
  }
  return count;
}
int main()
{
  char arr[]="bit";
  int len=strlen(arr);
  printf("len=%d\\n",len);
  return 0;
}

上述代码虽正确,但使用了临时变量,接下来我们尝试使用本节学习的递归知识来解决此问题:

int strlen(char* str)
{
  if(*str != '\\0');
  {
    return (1+strlen(str+1));//仔细体会此处递归的用法
  }
  else 
  return 0;
}
int main()
{
  char arr[]="bit";
  int len=strlen(arr);
  printf("len=%d\\n",len);
  return 0;
}

总而言之,递归其实就是函数通过调用自身来解决一些复杂的问题,它的原理非常简单,但想熟练使用却需要我们大量的练习。

在我们解决问题时,相较于不使用递归,递归的代码量会显得非常简洁,接下来的例子为大家展示递归函数的简洁性。

**例三:

【求n的阶乘】**

这里我先使用迭代方式来编写程序:

#include
int fac1(int x)
{
  int i=0;
  int ret=1;
  for(i=1;i<=x;i++)
  {
    ret=i*ret;
  }
  return ret;
}
int main()
{
   int a=0;
   scanf_s("%d",&a);
   int ret=fac1(a);
   printf("%d",ret);
   return 0;
}

上述代码使用了迭代的形式来编写代码,所谓迭代,其实就是函数内部的循环结构。我们在编程时使用迭代也能解决问题,但单单从代码的简洁性上来说,迭代是远远比不上递归的。接下来我们使用递归来解决上述问题:

#include
int fac2(int x)
{
  if(x<=1)
  return (x*fac(x-1));
}
int main()
{
   int a=0;
   scanf_s("%d",&a);
   int ret=fac2(a);
   printf("%d",ret);
   return 0;
}

如上述代码,我们仅用了一个if语句就完美地解决了问题,而上述的迭代却定义了两个临时变量加上使用了一个for循环才解决问题,递归写法的简洁性可见一斑了。

但并不是所有的代码都适合用递归来写,请看下面的例子:

**例四:

【求第n个斐波那契数】**

所谓斐波那契数,就是从1,1开始,一个数等于前两个数之和。

如 1,1,2,3,5,8,13,21......

其实此问题很好解决:

int fib(int n)
{
  if (n<=2)
    return 1;
  else
    return fib(n-1)+fib(n+1);
}
int main ()
{
  int a=0;
  int ret = 0;
  scanf_s("%d",&a);
  ret=fib(n);
  printf("%d ",ret);
  return 0;
}

经过测试,代码是可以完成任务的,但当我们想求第50个以上的斐波那契数时,我们会发现程序会运算很长时间,这时我们就会发现一个问题:在使用迭代运行程序时会造成计算力的大量浪费,这时使用递归就不是明智之举了,接下来我们使用迭代来编写该代码:

int fib(int n)
{
  int a=1;
  int b=1;
  int c=1;
  while(n>2)
  {
    c=a+b;
    a=b;
    b=c;
    n--;
  }
  return 0;
}
int main ()
{
  int a=0;
  int ret = 0;
  scanf_s("%d",&a);
  ret=fib(n);
  printf("%d ",ret);
  return 0;
}

这样程序就可以顺利运行了,我们这时就可以求可在int范围内存储的任意斐波那契数了。

到此,我们本节内容就结束了。递归和迭代这两种方法各有利弊,我们要灵活使用,我们下期将继续介绍C语言相关的知识。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 算法
    +关注

    关注

    23

    文章

    4629

    浏览量

    93287
  • 递归
    +关注

    关注

    0

    文章

    29

    浏览量

    9056
  • 程序调用
    +关注

    关注

    0

    文章

    3

    浏览量

    835
收藏 人收藏

    评论

    相关推荐

    32-代码复用与函数递归-3

    编程语言代码行业芯事经验分享
    硬件天空
    发布于 :2022年05月30日 14:27:47

    《C Primer Plus》读书笔记——递归

    本帖最后由 cugwyman 于 2017-2-5 20:14 编辑 递归的原理一个函数调用其本身,此调用过程为递归(recursion)。递归的使用举个栗子:/*用来测试UpA
    发表于 02-05 20:06

    LabVIEW递归

    感受到了递归的复杂和重要性。在爱因斯坦这一问题中,程序设计的时候反复递归,一个递归函数再调用另外一个递归
    发表于 02-19 11:52

    Labview递归函数的使用案例

    Labview递归函数的使用案例,简单的1+2+3...+100求和,简单易懂,充分理解递归函数的思想
    发表于 10-09 09:37

    LabVIEW中使用递归算法

    3! = 3*2*1 = 6。在下面附带的递归VI factorial.vi 例子通过将当前数与当前数-1的阶乘相乘而得,也就是调用了自己。 数学公式如下,3!=
    发表于 04-17 20:11

    C++教程之函数递归调用

    C++教程之函数递归调用 在执行函数 f 的过程中,又要调用 f 函数本身,称为函数递归
    发表于 05-15 18:00 35次下载

    递归指的是在函数的定义中使用函数自身的方法

    C语言支持递归,即一个函数可以调用其自身。但在使用递归时,程序员需要注意定义一个从函数退出的条件,否则会进入死循环。递归
    的头像 发表于 11-12 15:06 7171次阅读

    C++的实验教程之函数递归算法资料免费下载

    函数递归算法 1.范例:求组合数, 一、实验目的1. 学会解决简单的递归算法。2. 掌握函数的嵌套调用。
    发表于 01-29 10:51 2次下载
    C++的实验教程之<b class='flag-5'>函数</b>的<b class='flag-5'>递归</b>算法资料免费下载

    所有递归代码都可以转为非递归代码

    之所以所有的递归都能转为迭代算法是因为递归借助函数调用,函数调用本身就是基于调用栈这种结构实现的,只不过这一切都是自动完成的,我们当然也可以用代码手动模拟出来。
    的头像 发表于 04-19 15:02 2164次阅读

    C语言-内联函数递归函数、指针函数

    这篇文章介绍C语言的内联函数递归函数函数指针、指针函数、局部地址、const关键字、extern关键字等知识点;这些知识点在实际项目开发
    的头像 发表于 08-14 10:03 1728次阅读

    递归代码都转为非递归可以吗

    之所以所有的递归都能转为迭代算法是因为递归借助函数调用,函数调用本身就是基于调用栈这种结构实现的,只不过这一切都是自动完成的,我们当然也可以用代码手动模拟出来。
    的头像 发表于 02-17 14:35 792次阅读
    <b class='flag-5'>递归</b>代码都转为非<b class='flag-5'>递归</b>可以吗

    Python支持递归函数

    Python支持递归函数——即直接或间接地调用自身以进行循环的函数递归是颇为高级的话题,并且它在Python中相对少见。然而,它是一项应该了解的有用的技术,因为它允许程序遍历拥有任意
    的头像 发表于 02-21 14:28 676次阅读

    什么是Python的递归函数

    递归函数必须有终止条件。编程中,函数的调用要占用名叫栈(stack)的内存空间。调用函数时,程序会将相关的数据存储到计算机的栈里。
    的头像 发表于 02-23 10:25 1881次阅读

    C语言,你真的懂递归了吗?

    要说到递归如果不说栈的话,我觉得有点不合适,递归特点就是不断的调用同一个函数,如果这个函数没有一个递归界限,那么就是死循环了,所以讨论
    的头像 发表于 06-06 15:24 1061次阅读
    C语言,你真的懂<b class='flag-5'>递归</b>了吗?

    关于C语言中的递归

    递归指的是在函数的定义中使用函数自身的方法。
    发表于 02-26 10:34 431次阅读
    关于C语言中的<b class='flag-5'>递归</b>