浅谈递归函数—C语言

本文深入探讨了C语言中的递归函数,包括概念、必要条件和主要思想。通过计算阶乘和斐波那契数列的递归实现,以及汉诺塔问题的递归解法,阐述了递归在解决复杂问题时如何简化程序设计。同时,总结了递归程序设计的本质,强调在设计递归函数时应关注问题的自相似性和递归出口。
摘要由CSDN通过智能技术生成

浅谈递归函数—C语言

递归函数的概念

  1. 递归函数的定义:函数在其函数体内直接或间接调用它本身,则称该函数为递归函数。
  2. 递归的两个必要条件:(1)存在限制条件,当满足这个限制条件的时候,递归便不再继续;(2)每次递归调用之后越来越接近这个限制条件。
  3. 递归的主要思想:通过少量程序来描述解决问题过程所需的多次重复计算,即所谓的大事化小。
  4. 拓展:每一次调用递归函数时,计算机都会为该函数重新分配新的内存空间,并且将原递归函数暂停(可以理解为开副本),然后现场保存一下,即利用堆栈保存暂定位置,以及参数值保存。

例题

编程离不开示例,我们现在以例题帮我们加深对递归函数理解。
1.计算n!(1×2×3×·······×n)
先来看看整个的代码:

#include<stdio.h>
int Fac(int n)
{
	if (n <= 1)//0!=1  1!=1
		return 1;
	else
		return n*Fac(n - 1);//递归函数,自己调用自己
}
int main()
{
	int n = 0;
	scanf("%d", &n);//存储用户输入的值
	int ret = Fac(n);
	printf("%d\n", ret);
	return 0;
}

我们以n=3为例子,来看看下面这张图的思路
在这里插入图片描述
要用递归我要先找到需要重复计算的部分:n*Fac(n - 1),以及递归函数的出口n <= 1,有了这两个我们才可以设计程序。

拓展:每次调用递归函数,都会利用堆栈保存现场,以刚刚计算阶乘为例,其在堆栈保存如图所示,先入的放在最底下,这样返回的时候,程序就可以清晰的直到自己要去到什么位置,从什么位置继续执行程序,后面进入先出来,当然这是比较抽象理解,在计算机内部都是以二进制形式表示。
在这里插入图片描述
2. 计算斐波那契数
的确斐波那契数考虑到效率,较优解并不是以递归的形式,而是以迭代循环的形式计算,这里举例斐波那契数列只是为了了解递归。
首先理解什么是斐波那契数:

1 1 2 3 5 8 13 21 34......... 

从数学定义角度来看:
Fib(0)=1
F(1)=1
F(n)=F(n-1)+F(n-2)(n>=2,n∈N*)
可以直观看出斐波那契数列在n>=2后其值为前两项之和
同样先看看代码:

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

我们以n=3为例子,来看看下面这张图的思路:
在这里插入图片描述

要用递归我要先找到需要重复计算的部分:Fib(n - 1) + Fib(n - 2),以及递归函数的出口n <= 2,有了这两个我们才可以设计程序。

3.汉诺塔问题
汉诺塔游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置n个金盘,游戏目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。

为了方便理解,用动态图来表示:(图片来源知乎)
在这里插入图片描述
用递归的思想,我们要找到递归设计的两个重要部分:(1)重复部分,即自相似部分;(2)递归的出口。
(1)重复部分:不难发现,圆盘移动分三步:
第一步 把n-1个圆盘从A杆经C杆移动到B杆;
在这里插入图片描述
第二步 将A杆上第n个圆盘移动到C杆;
在这里插入图片描述
第三步 然后再将n-1个圆盘从B杆经A杆移动到C杆。
在这里插入图片描述
同理移动n-1个圆盘与移动n个圆盘是相识的,但是又有细微的不同,就是圆盘的插入杆变化了。

所以我就先制定函数的参数:
int hanoi(int n, char A, char B, char C)

//hanoi 汉诺塔
//n表示圆盘数
//上式子可以表示为将n个圆盘从A经B移动到C

提取重复部分:
hanoi(n - 1, A, C, B)
//将n-1个圆盘从A经C移动到B

move(A, C);
//将第n个圆盘从A移动到C

hanoi(n - 1, B, A, C)
//将n-1个圆盘从B经A移动到C

(2)递归函数的出口:
但N=1 时 ,只剩下一个圆盘直接移动到C杆就可以
move(A, C)
//本质是打印:A=====> C

#include <stdio.h>
int count = 0;//计算移动次数
void move(char x, char y)
{
	printf("%c =====>  %c\n", x, y);
	count++;
}
int hanoi(int n, char A, char B, char C)// n表示圆盘个数,A,B,C为三个杆子,表示从A经由B移动到C
{
	if (n == 1)
		move(A, C);
	else
	{
		hanoi(n - 1, A, C, B);
		move(A, C);
		hanoi(n - 1, B, A, C);
	}
}
int main()
{
	int n;
	printf("请输入圆盘数:\n");
	scanf("%d", &n);
	count=hanoi(n,'A','B','C');
	printf("总共移动%d次",count);
	return 0;
}

总结

  1. 递归程序设计的实质:把一个复杂的问题分解成若干子问题来处理时,其中某些子问题与原问题有相同的特征属性,则可以利用和原问题相同的分析处理方法(注意原问题与子问题能很好衔接)。
  2. 在设计递归函数时候,要将每个递归函数看成简单的操作, 不要想得过于复杂。
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值