C语言之递归函数、例题详解以及注意事项


目录

前言

一、递归的概念

二、递归例题详解

例1:斐波那契数列

例2:求次方

例3:求各位数之和

例4:阶乘

例5:顺序打印

三、递归的注意事项

总结


前言

        本文将和大家分享一些递归函数的相关知识,技巧与一些经验,希望对大家有所帮助,递归函数作为一种简洁的解题方法和特别的思维方式,非常值得我们去学习,而这种解题思路不太好想,最重要的还是多加练习,文中将举例一些我做过的递归题目来详细介绍递归,希望对大家有所帮助


一、递归的概念

在C语言中,递归简单来说就是函数自己调用自己,但是函数一味的自己调用自己就可能造成死递归,死递归就会导致栈溢出

如:

Stack overflow 即栈溢出

递归应当避免死递归

递归的中心思想:把一个大型复杂问题层层转化为一个与原问题相似,但规模较小的子问题来求解;直到子问题不能再被拆分,递归就结束了。所以递归的思考方式就是把大事化小的过程

递归递归,递推的意思,回归的意思。

因此,函数递归除了满足函数自己调用自己外,还有两个必要的条件:

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

以下将通过例题深入体会这两个限制条件


二、递归例题详解

例1:斐波那契数列

题目:使用递归实现求第n个斐波那契数列

题目分析:

  • 斐波那契数列:1  1  2  3  5  8  13  21  ...
  • 规律:即从第3位开始,该位数等于前两位数之和

递归分析:

  1. 为了实现递归,我们先找到一个临界条件,也就是递推的终点,回归的起点,该递归函数需要的参数只有n,即第n个斐波那契数列值,我们将函数命名为 Fib(n)
  2. 斐波那契数列只有从第三位开始才有前两项之和等于该项的规律,也就是当n>2时。当n<=2时,函数只需要返回1,
  3. 因此,我们可以设置n<=2为这个临界条件,每次调用该函数时都接近这个条件
  4. 例如,当n=5时,如下图分析:
  5. 下面我们就实现这个代码并验证这个结果:

这就是使用递归实现求斐波那契数列的代码,我们可以对比观察一下不使用递归实现求斐波那契数列的代码:

(注:该方法为,c为前两项之和,a,b分别为前2项和前1项,每次计算完c,就将b赋值给a,c赋值给b,实现逐步向后计算斐波那契数列)

对比发现:递归函数代码量非常少,却能实现一样的效果


例2:求次方

题目:编写一个函数实现n的k次方,使用递归实现。

分析:

  1. 众所周知,实现n的k次方,使用库函数pow即可实现,但现在需要使用递归实现,实现n的k次方,即n*n*n*...  递归函数的参数为n和k,我们将该函数命名为my_pow
  2. 同样,实现递归我们首先需要寻找限制条件,也就是递推与回归的临界条件,条件一般从参数上找,该函数有两个参数,我们先找到最底层的条件,也就是满足该条件时函数一定或应该返回什么。
  3. 不难想到,当k=1时,函数只需要返回n就行,当k不等于1时,我们需要再次调用该函数并接近这个临界条件,所以我们可以写成n*my_pow(n,k-1)
  4. 代码实现如下:
  5. 我们通过画图来理解:
  6. 当k不等于1时,计算n*my_pow(n, k-1),直到k=1,再逐渐返回计算值,这就是整个递归过程


例3:求各位数之和

题目:写一个递归函数DigitSum(n),输入一个非负整数,返回组成它的数字之和

例如:调用DigitSum(1729),则应该返回1 + 7 + 2 + 9,它的和是19

输入:1729,输出:19

分析:

  1. 该递归函数只有一个参数n,我们需要求每一位上的数之和,就需要得到每一位的数。不难想到,得到一个数的个位数只需要除10取余数就行,也就是%10,而得到十位数只需要先除以10就能消去个位数,再将得到的数%10就能得到十位数
  2. 我们再来确认限制条件,不难先想到最小的值,也就是n只有一位数时,即n<10时,这时候函数只需要返回n就行。当n为多位数时,我们需要先计算尾数,然后再调用该函数计算剩余的每一位数之和,而调用该函数时的参数需消除尾数,直到n仅剩一位数时递推结束
  3. 代码实现如下:
  4. 画图理解:
  5. 每一次递推将结果拆分为尾数+调用函数,直到n<10依次将结果返回


例4:阶乘

题目:递归实现求n的阶乘(不考虑溢出的问题)

分析:

  1. 阶乘:如5! = 5*4*3*2*1,阶乘的概念我们应该很清楚,通过5的阶乘我们可以发现 5! = 5* 4!,所以求5!我们可以转换求5*4!,以此类推下去...,除此之外我们需要知道0! = 1
  2. 因此我们可以将0作为限制条件,当n等于0时,函数返回1即可。当n>0时,函数返回n*(n-1)!即可,直到n等于0,递推结束,我们将函数命名为Factorial
  3. 代码实现如下:
  4. 我们画图分析:
  5. n不等于0时,不断地使n*(n-1),直到n等于0即可逐步返回


例5:顺序打印

题目:递归的方式实现打印整数的每一位数

例如:输入:4321

           输出:4 3 2 1

如果前面四道题全部能理清楚,那么这道题就不在话下了,只需要递归满足两个条件,一:限制条件,二:每次调用越来越接近这个条件即可。大家可以自己试着画图分析并且完成这道题

代码实现:


三、递归的注意事项

  • 关于递归和迭代的选取

        当我们学会递归后是不是发现递归的代码非常简单,并且递归和迭代相似,像一种套娃式的循环,那我们是不是遇到类似的问题就都使用递归呢?

        答案是否定的,递归虽好,却也有着局限

递归的局限性:如果计算数值过大,递归中就会存在大量重复计算,导致计算效率降低

例如我们的第一道例题:求斐波那契数列

假如我们使用递归求第50个斐波那锲数列,我们会发现计算机半天计算不出来

而我们使用迭代的方式发现,虽然计算结果是错的,但计算效率非常高,(结果错误是因为int类型存储大小的限制)

为什么递归半天计算不出结果,我们通过画图来解释:

我们可以发现,单就一个Fib(46)就计算了4次,而且越往下,重复计算就越多

我们可以打印看看求Fib(40),Fib(3)被计算了多少次:

Fib(3)居然被计算了三千多万次,这样大量的重复计算会导致代码效率非常低下

因此对于求斐波那契数列,用迭代的方式效率会高很多

总之,递归虽好,但也不是万能的,要根据实际问题选择是使用递归还是迭代


总结

        以上就是关于递归函数的一些知识,希望对大家有所帮助,感谢支持。

  • 46
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值