函数递归超详解!

目录

1.什么是递归调用?

直接调用

间接调用

2.什么是递归?

3.递归举例

3.1求n!的阶乘

3.1.1.非递归法

3.1.2.递归法

3.1.2.1分析和代码实现

3.2顺序打印一个整数的每一位

3.2.1分析和代码实现

4.递归与迭代

4.1举例:斐波那契数列

4.1.1迭代法

4.1.2递归法


1.什么是递归调用?

在调用一个函数出现直接间接地调用该函数本身,称为函数的递归调用

++直接调用++

cs 复制代码
void f()
{
...
...
f();//调用语句
...
}

++间接调用++

(下面这个代码中f函数调用了g函数,g函数又调用了f函数)

cs 复制代码
void f()
{
...
...
g();//调用g函数
...
}
void g()
{
...
...
f();//调用f函数
...
}

从以上两个函数可以看到,这两种递归调用都是无终止的自身调用。显然,程序中不应该出现这种无终止的递归调用,而只应该出现 有限次数 的、 有终止的 递归调用,这可以用if语句来控制,只有在某一条件成立时才继续执行递归调用;否则就不在继续。

2.什么是递归?

递归中的递就是递推,归就是回归

3.递归举例

3.1求n!的阶乘

3.1.1.非递归法

在进入递归之前,先体会一下非递归法

cs 复制代码
#include<stdio.h>
int   fac (int  n)   //n为形参
{  
    int i,m=1;
    for(i=1;i<=n;i++)
    {
        m=m*i; //用循环累乘:m=1*2*...*n
    }
   return m;
}
int  main()
{
    int n,y;
    scanf("%d",&n);//输入n
    y=fac(n);//n为实参
	printf("%d!=%d",n,y);
return 0;
}

(注:实参和形参可以重名,如果主程序中输入n值是4,调用函数时,则是把其值4传递给函数的形式参数n,形参n的值即为4,实参仅是做的一个值的传递,这个过程与实参的名字是什么无关,所以形参和形参名字相同不影响传值调用

3.1.2.递归法
3.1.2.1分析和代码实现

n!=n*(n-1)!

4!=4*3*2*1

3!=3*2*1

所以:4!=4*3!

当n==0的时候,阶乘为1,其余用公式计算

先将整体代码列给大家

cs 复制代码
#include"stdio.h"
int fact(int n)
{
	if(n==0)
		return 1;
	else
		return n*fact(n-1);
}
	
int main()
{
	int n=0;
	scanf("%d",&n);
	int r=fact(n);
	printf("%d!=%d",n,r);
    return 0;
}

下面用n=5时的例子给大家解释

fact(5)虽然=5*fact(4),但是fact(4)又是一个调用函数,再次调用fact函数,然后求得fact(4)为多少后,别忘记乘上前面的5,也可按照上图一步一步算

因为你调用完得出的值得返回去

递归是用少量的代码完成大量复杂的运算

3.2顺序打印一个整数的每一位

分析:输入一个整数,按照顺序打印一个整数的每一位

eg:

输入:1234 输出:1 2 3 4

3.2.1分析和代码实现

1234

1234%10=4

1234/10=123

123%10=3

123/10=12

12%10=2

12/10=1

1%10=1

1/10=0

以上的方法很容易理解,但是过于复杂,所以下面我们用递归的方法解决此问题

仔细分析上图解析,可以的得出此代码为

cs 复制代码
#include<stdio.h>
void print(int n)
{
	if (n > 9)
		print(n / 10);
	printf("%d ", n % 10);
}
int main()
{
	int n = 0;
	scanf_s("%d", &n);
	print(n);
	return 0;
}

4.递归与迭代

fact函数是可以产生正确的结果,但是在递归函数中涉及一些运行时的开销。

在c语言中每一次函数调用,都需要为本次函数调用在内存的栈区申请一块内存空间来保存函数调用期间的各种局部变量的值,这块空间被称为运行时堆栈 ,或者函数栈帧

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

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

所以我们可以使用迭代的方法(循环)

cs 复制代码
#include<stdio.h>
int fact(int n)
{
	int i = 0;
	int ret = 1;
	for (i = 1; i <= n; i++)
	{
		ret *= i;
	}
	return ret;
}
int main()
{
	int n = 0;
	scanf_s("%d", &n);
	int r = fact(n);
	printf("%d", r);
	return 0;
}

注:当一个问题非常复杂,难以用迭代的方法实现时,此时递归实现的简洁性便可以补偿它所带来的开销。

4.1举例:斐波那契数列
4.1.1迭代法
cs 复制代码
#include<stdio.h>
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 c;
}

int main()
{
	int n = 0;
	scanf_s("%d", &n);
	int r=fib(n);
	printf("%d\n", r);
	return 0;
}
4.1.2递归法
cs 复制代码
#include<stdio.h>
int count = 0;
int fib(int n)
{
	if (n == 3)
		count++;

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

注意:此题使用迭代法(非递归法)更好,因为递归法计算时,会有重复计算, 下图我们看到,

在计算第40个斐波那契数列时,第三个斐波那契数被重复计算了39088169次,这就会非常复杂。

而用迭代是,从小往大加就行了。

相关推荐
极客代码3 分钟前
【Python TensorFlow】进阶指南(续篇三)
开发语言·人工智能·python·深度学习·tensorflow
土豆湿9 分钟前
拥抱极简主义前端开发:NoCss.js 引领无 CSS 编程潮流
开发语言·javascript·css
小陈phd10 分钟前
Vscode LinuxC++环境配置
linux·c++·vscode
界面开发小八哥16 分钟前
更高效的Java 23开发,IntelliJ IDEA助力全面升级
java·开发语言·ide·intellij-idea·开发工具
火山口车神丶25 分钟前
某车企ASW面试笔试题
c++·matlab
jiao_mrswang36 分钟前
leetcode-18-四数之和
算法·leetcode·职场和发展
qystca44 分钟前
洛谷 B3637 最长上升子序列 C语言 记忆化搜索->‘正序‘dp
c语言·开发语言·算法
薯条不要番茄酱1 小时前
数据结构-8.Java. 七大排序算法(中篇)
java·开发语言·数据结构·后端·算法·排序算法·intellij-idea
今天吃饺子1 小时前
2024年SCI一区最新改进优化算法——四参数自适应生长优化器,MATLAB代码免费获取...
开发语言·算法·matlab
是阿建吖!1 小时前
【优选算法】二分查找
c++·算法