C语言递归及经典例题详解

 什么是递归?

什么时候使用递归

例题1 顺序打印问题

例题2 求n的阶乘

例题3 求第n个斐波那契数

经典 汉诺塔问题

经典 青蛙跳台阶问题 

什么是递归?

递归就是程序调用自身的编程技巧。递归通常把一个大型复杂的问题层层转化为一个与原问题相似,规模较小的问题来求解。递归策略只需要少量的程序就可以描述出解题过程所需要的多次重复的计算,大大减少程序的代码量。

递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。

什么时候使用递归?

1、大问题可以拆分成若干小问题。

2、原问题与子问题除数据规模不同,求解思路完全相同。

3、存在递归终止条件。

4、当不满足终止条件时,要如何缩小函数值,并让其进入下一层循环中。

例题1 顺序打印问题:

输入一个整数123,依次在屏幕打印1 2 3 

代码:

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

例题分析:本题的思路不断拆分整数,并将他们一一打印,只要n>10,就另n不断除以10,不断的递归调用n/10,当n<10时,满足递归终止条件,令n%10,此时我们得到的是此数的最高位。当打印完最高位时返回,继续打印不一定是个位数,所以%10只保留个位。

例题2 求n的阶乘:

代码:

int Fac(int n)
{
	if (n == 1)
	{
		return 1;
	}
	return n*Fac(n - 1);
}
int main()
{
	int n = 0;
	scanf_s("%d", &n);
	int ret = Fac(n);
	printf("%d", ret);
	return 0;
}

例题分析: 求n!就是不断求n*(n-1)的过程,而这个过程又分为2种情况,当n=1时,n!=1;当n>1时,n!=n*Fac(n-1)。我们求Fac(n),就是不断求Fac(n-1)的过程,当不断递归求到Fac(1)时,依次计算阶乘返回,最终得到n!

例题3 求斐波那契数列

求第n个斐波那契数

代码:

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

例题分析:斐波那契数列就是前两个数为1,从第3个数开始,所有数都为前两个数的和。这样的话我们可以分成两种情况,一种是n<=2时,第n个斐波那契数的值为1;当n>2时,第n个斐波那契数的值为Fib(n-1)+Fib(n-2)。

经典 汉诺塔问题:

该问题的主要材料包括三根高度相同的柱子和一些大小及颜色不同的圆盘,三根柱子分别为起始柱A,辅助柱B及目标柱C。

操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于任意杆上。

问题分析:为了便于理解,我们首先分析3个盘子的移动过程:

1、将A柱上的两个盘子移动到B柱(借助C)

2、将A柱上的一个盘子移动到C柱

3、将B柱上的2个盘子移动到C柱(借助A)

其中,第2步直接将最大盘放到C柱可直接实现。

第1步又可以分解为:

1.1 将A柱上的一个盘子移动到C

1.2 将A柱上的第二个盘子移动到B

1.3 将C柱上的盘子移动到B

 

第3步又可以分解为:

3.1 将B柱的第一个盘子移动到A柱

3.2 将B柱的第二个盘子移动到C柱

3.3 将A柱的一个盘子移动到C柱

 综上可以得到3个盘子的移动步骤:

A->C

A->B

C->B

A->C

B->A

B->C

A->C

以上3个盘子移动共经历了7步完成。

从这里我们可以推出规律:如果有n个盘子移动,一共会经历2^n-1步。 

所以如何移动n个盘子呢?

道理和3个盘子移动是一样的,移动过程如下:

1、将A柱上的n-1个盘子移动到B柱(借助C)

2、将A柱上的一个盘子移动到C柱

3、将B柱上的n-1个盘子移动到C柱(借助A)

代码: 

#include <stdio.h>
void move(char x, char y)
{
	printf("%c-->%c\n", x, y);
}
void hanoi(int m, char one, char two, char three)
{
	if (m == 1)
	{
		move(one, three);
	}
	else
	{
		hanoi(m - 1, one, three, two);
		move(one, three);
		hanoi(m - 1, two, one, three);
	}
}
int main()
{
	int m = 0;
	printf("请输入移动盘子的数量:>\n");
	scanf_s("%d", &m);
	hanoi(m, 'A', 'B', 'C');
	return 0;
}

移盘方案:

经典 青蛙跳台阶问题: 

一只青蛙一次可以跳上一级台阶,也可以跳上2级,求该青蛙跳上n级的台阶总共有多少种跳法(先后次序不同算不同结果)。

例题分析:此题可以分为台阶有1,2,3....n级台阶。

台阶为1级时:有1种跳法

台阶为2级时:有2种跳法

台阶为3级时:有3种跳法

台阶为4级时:有5种跳法

........

台阶为n级时:有(n-1)+(n-2)种跳法

代码:

int jumpFloor(int m)
{
	if (m == 1)
	{
		return 1;
	}
	else if (m == 2)
	{
		return 2;
	}
	else
	{
		return jumpFloor(m - 1) + jumpFloor(m - 2);
	}
}
int main()
{
	int target = 0;
	printf("请输入青蛙所要跳的台阶数:>\n");
	scanf_s("%d", &target);
	int ret = jumpFloor(target);
	printf("%d\n", ret);
	return 0;
}

感谢阅读,欢迎大家批评指正!

  • 47
    点赞
  • 220
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
Hanoi塔是一个经典递归问题,它可以用C语言来实现。Hanoi塔问题的规则是,有三根柱子A、B、C,以及n个不同大小的圆盘,初始时,所有圆盘都放在柱子A上,目标是将所有圆盘从A柱子移动到C柱子上,每次只能移动一个圆盘,并且大的圆盘不能放在小的圆盘上面。 要解决Hanoi塔问题,可以使用递归的方法。递归的思想是将大问题分解成一个个小问题来解决,然后通过组合小问题的解来解决整个问题。 在这个问题中,我们可以将n个圆盘的移动分解为三个步骤: 1. 将n-1个圆盘从A柱子移动到B柱子上; 2. 将最大的一个圆盘从A柱子移动到C柱子上; 3. 将n-1个圆盘从B柱子移动到C柱子上。 这样,问题就被分解成了三个小问题,而这三个小问题与原问题的规模相比减小了,因此可以使用递归的方法来解决。 具体的C语言递归代码如下: ```c void hanoi(int n, char source, char auxiliary, char target) { if (n == 1) { // 只有一个圆盘时,直接从source柱子移动到target柱子上 printf("Move disk from %c to %c\n", source, target); return; } hanoi(n-1, source, target, auxiliary); // 递归调用步骤1 printf("Move disk from %c to %c\n", source, target); // 移动最大的圆盘 hanoi(n-1, auxiliary, source, target); // 递归调用步骤3 } int main() { int n; printf("Enter the number of disks: "); scanf("%d", &n); hanoi(n, 'A', 'B', 'C'); // 调用递归函数 return 0; } ``` 通过上述C语言代码,我们可以递归地解决Hanoi塔问题,并输出每一步的移动方式。这个递归方法的时间复杂度是O(2^n),因为每个圆盘都要移动2^n次。但是由于递归的特性,它的空间复杂度是O(n),因为每次递归调用时需要保存函数的局部变量。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mikk-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值