函数(二):函数的递归

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

  函数的递归在学习编程基础中一度被认为较难的问题,这类问题如果纠结于递归的细节,每一层到底是如何运行的?特别是遇到较难的问题时,例如汉诺塔问题时,想通过调试去了解其细节,对于水平不高的初学者来说,很容易被绕晕。所以学习·递归时我们应该总体把握,淡化细节,才能更容易理解递归。

一、什么是递归

程序调用自身的编程技巧称为递归( recursion)。 递归做为一种算法在程序设计语言中广泛应 用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复 杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可 描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。 递归的主要思考方式在 于:把握住整体思路,把大事化小。

递归的两个必要条件

1存在限制条件,当满足这个限制条件的时候,递归便不再继续。

2每次递归调用之后越来越接近这个限制条件。

二.为什么要用递归

从上述可知递归的主要作用是把大事化小,把复杂的问题简单化。在现实生活中遇到复杂的问题总会想办法简化它,但是很难想到一步就把问题变得通俗易懂。所以我们先想到把一个问题进行调整,每一次使问题简化一点,直到它能够被简单解决。在这个过程中这个简化方法应该是通用的,即对简化过后的数据再次进行简化,如果我们把这个方法写成一个函数,就会出现函数自己调用自己的情况。这样来看我们只需要想到一个总体思路,让程序按照这个思路一步步进行递归就行了,这样就能够淡化其细节,不用每一步都细究,问题自然得到简化。

三:例题分析

1:求n的阶乘

1:思路:我们告诉计算机求n的阶乘,可是计算机说:“我会加减乘除,阶乘是什么鬼?”,这时我们想如何把阶乘转换为乘积呢?例如我们求5的阶乘,我们告诉计算机,5的阶乘=5×4的阶乘,可是计算机又不认识4的阶乘,那我们只能再按照这个思路,把4的阶乘=4×3的阶乘,这样操作下去,最终会得到2的阶乘=2×1的阶乘,这时我们告诉计算机,1的阶乘是1,通过这样的处理我们把阶乘这个计算机不认识的概念转换化为求多个数的乘积。这个总体思路能把n(>=2)的阶乘全转化为1的阶乘×常数的形式,我们就能轻易算出n的阶乘了。

2:图例

 通过这个图相信大家能更深入的了解递归,递归分为递推和回归,如图向下指的箭头是递推,往回指的是回归,递推的目的是通过不断重复函数自身的特定功能,把问题一步步简化,例如本图通过这个总思路能把n的阶乘一步步转化到1的阶乘,而1的阶乘是我们能够简单处理的问题,于是递推停止,现在我们要解决问题并把结果一步步返回。

代码如下:

#include<stdio.h>
int Factorials(int n)//这里求n的阶乘
{
	
	if (n >= 2)
	{
		return Factorials(n - 1) * n;//如果n>=2,利用递归对问题进行层层简化,直到转化为1的阶乘
	}
	if (n == 1)
	{
		return 1;
	}
}
int main()
{
	int n;
	scanf("%d", &n);
	int ret=Factorials(n);
	printf("%d ", ret);
	return 0;
}

看到这段代码大家可能还有些不理解,但如果大家跳出来,从总体来看。这个问题就简化成了,我告诉电脑如果是大于2的阶乘就可以转化为n×(n-1)的阶乘,这样电脑就会一直重复下去,直到转换为1的阶乘,最终我要它把乘法运算结果给return回来就可以了。

2:输入一个整数,要求把它的每一位依次输出

例如输入:1234   输出1 2 3 4

1:思路:我们知道对于一个非0两位以上整数,我们将它%10可以得到它的最后一位,将它/10可以得到除最后一位之外的数。

2:图例

 从这个图我们可以知道,每一步使用print函数时,它执行的功能都是相同的先把最后一位拿下来,再把剩下的位再次进行相同的操作,等到回归时再打印数字。从中我们也可以看到递归的规律,先按照总体思路层层递进,不段靠近限制条件(这题限制条件是两位数),被限制条件限制后,执行违反条件的语句(这题是1不是两位数,所以把1打印出来),然后进行回归,回到上一次调用自己的地方(这里从1回归到12),再用12%10把2打印出来,这样下去就可以把1234分别打印出来。

简化过程:四位数依次打印-->三位数依次打印.........-->一位数依次打印

 3.代码展示

#include<stdio.h>
void print(int num)
{
	if (num >= 10)//如果是两位数以上才需要不断执行这种方式化简
	{
		print(num / 10);//在这里进行层层递进,每次递进前都要进行条件判断
	}
	printf("%d ", num % 10);//回归时num=1 12 123 1234
}
int main()
{
	int num;
	scanf("%d", &num);
	print(num);
	return 0;
}

 3:汉诺塔问题的求解(难)

如果大家不知道汉诺塔问题的话,请大家百度了解一下,效果更好。

想要解决n层汉诺塔问题,我们首先就要解决2层汉诺塔问题,对于两层汉诺塔需要三步,第一步把A柱上的小盘子放到B柱上,第二步把A柱的大盘子移到C柱子上,第三步把B柱子上的盘子移到C柱子上。而对于n层汉诺塔问题,其本质上就是两层汉诺塔问题,我们可以把n层汉诺塔分为最大的盘子和n-1个较小的盘子这两类盘子。然后依旧是三步走,第一步把n-1层汉诺塔从A柱移到B柱子,注意每次只能移动一个盘子所以,n-1个盘子必须从A柱开始借助B柱子到达C柱子,那么第一步其实等价于完成一次n-1层汉诺塔问题(把n-1个盘子从一个柱子完全移动到另一根柱子)此处要用递归简化。第二步把A柱上的一个盘子从A移到C(一个盘子完全可以直接移动,已经是最简形式),第三步把n-1个盘子从B住开始借助A移动到C柱子。然后就可以用递归来重复这个思路,直到化简为移动一个盘子为止。 

 总代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//双重递归之汉诺塔的求解
void move(char x, char y)
{

	printf("%c--->%c\n", x, y);

}

void Hannuo(int n, char A, char B, char C)
{
	if (n == 1)
	{
		move(A, C);
	}
	else
	{
		Hannuo(n - 1, A, C, B);
		move(A, C);
		Hannuo(n - 1, B, A, C);
	}

}

int main()
{
	int n;
	printf("请输入你要求解的汉诺塔的层数:");
	scanf("%d", &n);
	Hannuo(n, 'A', 'B', 'C');
	return 0;
}

 效果展示:

总结

现在我们对这三个问题进行总结:对于第一求阶乘的例子我们通过递归转换为求1的阶乘。第二题把两位以上的整数依次输出,我们通过递归简化为把一位数输出。第三题汉诺塔问题,我们通过把它看成两个盘子,让n层汉诺塔转换位n-1层汉诺塔,一步步简化直到简化为一个盘子的移动,相信大家能感受到递归是一种调整,不断把问题简单化的调整。

由于本人水平有限,有些地方解释不够细致还望大佬即使斧正,如果想要讲解更多的递归题目可以,私信我,多多关注点赞,谢谢大家见证我的成长。 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值