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

    文章

    4456

    浏览量

    90760
  • 递归
    +关注

    关注

    0

    文章

    28

    浏览量

    8976
  • 程序调用
    +关注

    关注

    0

    文章

    3

    浏览量

    799
收藏 人收藏

    评论

    相关推荐

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

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

    Labview递归函数的使用案例

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

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

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

    现代C函数式编程

    和技巧,同时也体现了现代C++的强大威力和无限可能。 概述 函数式编程是一种编程范式,它有下面的一些特征: 函数是一等公民,可以像数据一样传来传去。高阶函数递归pipeline惰性求值
    发表于 09-30 16:43 2次下载

    函数式编程语言、编程和程序验证

    是1930年代在调查函数定义、函数应用和递归时研发的一个形式系统,是等价于图灵机的一种抽象的计算模型,许多函数式编程语言都可看成是在演算基础上精心制作出的结果
    发表于 04-03 11:01 3次下载

    通过PICC编译环境下,对PIC单片机程序进行操作研究

    PICC基本上符合ANSI标准,但是不支持函数递归调用,其主要原因是PIC单片机特殊的堆栈结构。PIC单片机中的堆栈是硬件实现的,其深度已随芯片固定,无法实现需要大量堆栈操作的递归算法;另外在PIC单片机中实现软件堆栈的效率也
    的头像 发表于 09-25 15:53 3391次阅读
    通过PICC编译环境下,对PIC单片机程序进行操作研究

    C++语言入门教程之C++语言程序设计函数的详细资料概述免费下载

    本文档的主要内容详细介绍的是C++语言入门教程之C++语言程序设计函数的详细资料概述免费下载内容包括了:1 函数的定义和使用2 函数的参数传递3 函数的嵌套调用4
    发表于 09-20 14:51 23次下载

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

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

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

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

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

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

    Python支持递归函数

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

    函数递归-1

    在我看来,如果说各种循环与分支是一个系统的骨架的话,那么形式繁多的函数就是C语言的血肉了,正是各式各样的函数决定了C语言的各种功能。那么话不多说,既然函数如此重要,那就快跟我一起了解函数
    的头像 发表于 02-21 15:50 337次阅读
    <b class='flag-5'>函数</b>与<b class='flag-5'>递归</b>-1

    函数递归-2

    传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式 此传参方式可以让函数函数外面的变量建立起真正的联系。也就是说,
    的头像 发表于 02-21 15:53 334次阅读
    <b class='flag-5'>函数</b>与<b class='flag-5'>递归</b>-2

    什么是Python的递归函数

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

    递归函数计算斐波那契数列中的第n项值

    编写一个递归函数,用于计算斐波那契数列中的第n项值,并在主函数中调用该函数输出斐波那契数列的前15项。
    的头像 发表于 06-07 11:30 1905次阅读