c语言入门——函数的递归
一.什么是递归?
程序调用自身的编程技巧称为递归( recursion)。
递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接 调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解, 递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归的主要思考方式在于:把大事化小
二.递归的两个必要条件
1.存在限制条件,当满足这个限制条件的时候,递归便不再继续。
2.每次递归调用之后越来越接近这个限制条件。
三.递归的应用
首先先举一个简单的例子
1.n的阶乘
n的阶乘,是将从1到n之间的整数相乘。
按照迭代的方式,我们可以通过循环来完成这个工作
int i;
int n;
int fac=1;
scanf("%d",&n);
for(i=1;i<=n;i++)
{fac=fac*i;
}
而我们也可以按照递归的方式来完成
首先我们需要创建一个函数Fac(n)
根据递归的概念,我们可以初步确定这个函数
而根据递归的思想,我们可以将函数看作以下方式
同理,Fac(n-1)=(n-1)*Fac(n-2)
而当n=1时,阶乘应该停止,所以我们将限制条件设置为n>1。
以此类推,每次函数调用都会接近n>1这个限制条件,我们便可以以递归的方式完成n的阶乘
int Fac(int n)
{if(n>1)return n*Fac(n-1);elsereturn 1;
}
int main()
{int n;scanf("%d",&n);int fac=Fac(n);return 0;
}
2.顺序依次打印整形值
例如一个整形值num=1234
想要顺序打印,我们首先需要获取这个整形值每一位的数字
我们首先想到的便是利用取商和取余
num/10=123
num%10=4
而函数结束的条件应为print()的参数num=0,由此我们可以确立这个函数
void Print(int num)
{if(num>0){Print(num/10);printf("%d ",num%10);}elseprintf("\n");
}
int main()
{int num;scanf("%d",&num);Print(num);
}
四.递归与迭代
1.递归出现的问题
(1).运行时间长
首先我们先看一下递归方法下的斐波那契数列
int fib(int n)
{if (n <= 2) return 1;elsereturn fib(n - 1) + fib(n - 2);
}
当n的值较小时,我们可以轻易的求出第n个斐波那契数
而n的值较大时,计算的时间便被大大延长
那么这是为什么呢?
我们可以看到,在递归形式下的菲波那切数列,随着递归的进行,会出现重复的调用。
而随着n的增大,递归次数增多,重复调用的问题也会更加严重,严重影响程序运行时间。
我们可以将代码作出以下修改
int count = 0;
int fib(int n)
{if(n == 3)count++;if (n <= 2) return 1;elsereturn fib(n - 1) + fib(n - 2);
}
这样,我们便可以根据count的值来判断fib(3)所调用的次数
当n等于20时,fib(3)就已经被调用了2584次,严重影响程序运行时间。
(2).栈溢出的报错
在上面所举的n的阶乘的例子中
int Fac(int n)
{if(n>1)return n*Fac(n-1);elsereturn 1;
}
int main()
{int n;scanf("%d",&n);int fac=Fac(n);return 0;
}
若让n=10000,程序会发生崩溃,会报错: stack overflow(栈溢出)
这有是为什么呢?
这是由于每一次调用函数,都会为本次函数在内存的栈区上开辟一块内存空间,系统分配给程序的栈空间是有限的,因此递归层数过深会导致栈空间耗尽,这种现象称为栈溢出。
2.解决方法
(1). 将递归改写成非递归。
(2). 使用static对象替代 nonstatic 局部对象。 在递归函数设计中,可以使用 static 对象替代 nonstatic 局部对象(即栈对象),这不仅可以减少每次递归调用和返回时产生和释放 nonstatic 对象的开销,而且 static 对象还可以保存递归调用的中间状态,并且可为各个调用层所访问。
3.其他
(1). 许多问题是以递归的形式进行解释的,这只是因为它比非递归的形式更为清晰。 但是这些问题的迭代实现往往比递归实现效率更高,虽然代码的可读性稍微差些。
(2). 当一个问题相当复杂,难以用迭代实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开销。
总结
本篇文章只是对函数递归进行了最初步的讲解,而如果想要熟练使用函数递归解决问题,需要我们进行大量的思考练习。
这里提供两个函数递归的经典问题供大家思考:
1. 汉诺塔问题
2. 青蛙跳台阶问题
c语言入门——函数的递归相关推荐
- 在c语言中允许函数递归调用,c语言允许函数的递归调用吗
c语言允许函数的递归调用吗 允许.C语言中的函数直接或间接调用自己的过程叫递归. 一.递归的两个必要条件 1.存在限制条件,当满足这个条件时,递归便不再继续. 2.每次递归调用之后越来越接近这个限制条 ...
- c语言入门---函数
目录标题 一.前言 二.函数是什么 三.c语言中函数的分类 四.为什么会有库函数 五.如何使用库函数 六.为什么会有自定义函数 七.如何来创建自定义函数 八.函数的参数 1.实际参数(实参) 2.形式 ...
- <C语言> 函数与递归
函数 1.函数的分类 库函数 自定义函数 1.1 库函数 C语言提供了许多库函数(library functions)来简化开发过程并提供常用功能的实现.库函数是预先编写好的函数,可以通过调用这些函数 ...
- C语言:函数的递归调用
函数的递归调用:一个函数在它的函数体内,直接或者间接地调用了他本身. 直接递归调用:函数直接调用自身. 间接递归调用:函数间接调用自身. 如下 ...
- C语言入门-函数专辑(一)
函数的概念 函数是一段可以重复使用的代码,用来独立地完成某个功能,它可以接收用户传递的数据,也可以不接收. 函数的类型 C语言中函数一般分为两类. 一类是库函数,即系统自带函数,如printf.sca ...
- C语言丨函数的递归调用和递归函数
目录 前言 一.从阶乘引入 二.递归模板 1.递归函数模板 2.举例分析 三.从数学归纳法理解递归 四.更多递归实例 1.用递归方法编程计算Fibonacci数列 题目分析 程序 2.汉诺塔(Hano ...
- 超详细讲解C语言入门函数(一)
解析已经很详细了,可以说相当入门级别了,如果喜欢的话那就请支持一下,后续会继续更新~ 代码网上搜索,并加以更改,侵权请联系删除,谢谢~ 部分例子没有详细解释是因为前面的例子已经说过了 3×4矩阵求最大 ...
- c语言入门函数大全,C语言函数大全(适合初学者).doc
C语言函数大全(适合初学者)C语言函数大全(适合初学者) A 函数名: abort 功 能: 异常终止一个进程 用 法: void abort(void); 程序例: #include #includ ...
- C语言入门 - 什么是递归?
什么是递归? 递归就是自己调用自己,相当于循环: - 直接递归调用 - 间接调用:通过其他**调用 #include<stdio.h> #include<stdlib.h> v ...
最新文章
- php多进程共享数据库,PHP多进程环境下通过共享内存与信号量实现资源共享
- springmvc十七:自定义视图和自定义视图解析器
- 深圳内推 | 腾讯AI Lab自然语言处理中心招聘NLP研究型实习生
- 学完java后学编译原理_一个资深程序员对Java初学者的学习思维路线建议
- PHP100视频教程2012版解压密码
- windows下面使用nssm设置新的服务实现开机自启等
- iPhone黑屏幕转圈圈(解决办法)
- mybatis按datetime条件查询,参数为时间戳时
- Python 之父从 Dropbox 退
- 亲密关系沟通-【唤起亲密】-在平淡关系中创造高质量沟通
- 【PYTHON笔记】:文件打开和关闭
- ValueError:Tensor(dense_1/Softmax:0, shape=(?, 3), dtype=float32) is not an element of this graph
- Arduino ISP下载接口
- 程序员接私活完整攻略
- [论文笔记]Vision-based Control of 3D Facial Animation
- 被罚6500万,“偷税人”雪梨还能直播吗?
- 谷歌雅虎新闻大战-两种路线的PK
- Android加载so库
- antv g2字体阴影_antv-g2学习手册-中
- C语言编写九九乘法表,实现不同三角形形状表格输出