详解C语言函数递归经典问题:汉诺塔(图+代码)

第一次接触汉诺塔是在谭浩强的那本红书上,当时看了半天也不明白,后来接触递归题目逐渐变多才理解汉诺塔问题。

一.汉诺塔问题

首先让我们先回顾一下汉诺塔问题是什么:一块板上有三根针 A、B、C。A 针上套有 n 个大小不等的圆盘,按照大的在下、小的在上的顺序排列,要把这 n个圆盘从 A 针移动到 C 针上,每次只能移动一个圆盘,移动过程可以借助 B 针。但在任何时候,任何针上的圆盘都必须保持大盘在下,小盘在上。从键盘输入需移动的圆盘个数,给出移动的过程。

这里对问题进行分析。目标:将圆盘从A移到C,顺序还是从大到小(从下到上)。规则:大的圆盘不能放在小的圆盘上。

如果在闹中模拟简单的汉诺塔还是可以轻松移好的,但把汉诺塔实现在程序里就难理解很多。

二.汉诺塔中的递归

我们先看一下简单三个圆盘的移动过程:详解C语言函数递归经典问题:汉诺塔(图+代码)_第1张图片

详解C语言函数递归经典问题:汉诺塔(图+代码)_第2张图片

详解C语言函数递归经典问题:汉诺塔(图+代码)_第3张图片

详解C语言函数递归经典问题:汉诺塔(图+代码)_第4张图片

详解C语言函数递归经典问题:汉诺塔(图+代码)_第5张图片

详解C语言函数递归经典问题:汉诺塔(图+代码)_第6张图片

详解C语言函数递归经典问题:汉诺塔(图+代码)_第7张图片

详解C语言函数递归经典问题:汉诺塔(图+代码)_第8张图片

以上就是三个圆盘的汉诺塔问题过程图。

上述过程中有一个关键的过程就是下方这个:

详解C语言函数递归经典问题:汉诺塔(图+代码)_第9张图片

其实不管是多少个圆盘,他们之中一定有这一步,就是最大的圆盘在C,其余所有的圆盘的B。

详解C语言函数递归经典问题:汉诺塔(图+代码)_第10张图片

完成上面步骤就是为了完成下列步骤:

详解C语言函数递归经典问题:汉诺塔(图+代码)_第11张图片

以此类推,最终就所有的圆盘全部放到C上。

这里面其实就有递归的思想,要完成这一步我们先要完成这一步,不断往前推。

比如我们要完成这一步:

详解C语言函数递归经典问题:汉诺塔(图+代码)_第12张图片

就要先完成这一步:

详解C语言函数递归经典问题:汉诺塔(图+代码)_第13张图片

这不就是一个典型的递归过程吗

递归的题目怎么解呢?先找一个表达式,就是能解释要求是结果的式子,如求阶乘的式子:f(n)=n*f(n-1)。在就直接写一个函数递归就可。

汉诺塔一样也是找一个“式子”,不过这个式子是抽象的,可以理解成一个关键的步骤:一共n个圆盘,把(n-1)个圆盘从A移到B,在把最大的圆盘从A移到C,最后把B上的所有圆盘从B移到C。就是这么一个过程。

三.代码详解

我们要写两个函数,一个使用来打印移动的,一个是汉诺塔函数

void move(char pos1, char pos2)
void hanoi(int n, char pos1, char pos2, char pos3)
1.打印过程函数

首先先说一下打印函数:

void move(char pos1, char pos2)
{
	printf(" %c->%c ", pos1, pos2);
}

简单明了,就是打印从哪移到哪。注意:从这函数可以看出,汉诺塔它不是真的移动了只是利用函数的递归打印出步骤的。

2.汉诺塔函数

再说一下重点函数,汉诺塔函数:

void hanoi(int n, char pos1, char pos2, char pos3)
{
	if (n == 1) move(pos1, pos3);
	else
	{
		hanoi(n - 1, pos1, pos3, pos2);
		move(pos1, pos3);
		hanoi(n - 1, pos2, pos1, pos3);
	}
}

先解释一下参数是什么:

n是圆盘个数,pos1是起始位置,pos2是中转位置,pos3是目标位置

注意:pos1,pos2,pos3不是和ABC一一对应的,他们会随着各种位置变化而变化,pos1可能是A也可能是B和C,具体情况要看具体分析。

如果就一个圆盘,不用多说,直接从A移到C;两个圆盘要先把小的放在B上,把大的放在C上,最后把小的放到大的上面。这是就牵扯到了上面的递归思想,一共2个圆盘,把1个圆盘从A移到B,在把最大的圆盘从A移到C,最后把B上的所有圆盘从B移到C。如果是三个圆盘呢,一样的步骤所有我们写出了一下代码:

hanoi(n - 1, pos1, pos3, pos2);
move(pos1, pos3);
hanoi(n - 1, pos2, pos1, pos3);

第一个:把除了最大的圆盘通过C的中转全部移动到B上

第二个:把最大的圆盘从A移到C

第三个:把B上的圆盘通过A的中转移动到C上

3.完整代码
#include
void move(char pos1, char pos2)
{
	printf(" %c->%c ", pos1, pos2);
}
void hanoi(int n, char pos1, char pos2, char pos3)
{
	if (n == 1) move(pos1, pos3);
	else
	{
		hanoi(n - 1, pos1, pos3, pos2);
		move(pos1, pos3);
		hanoi(n - 1, pos2, pos1, pos3);
	}
}
int main()
{
	int n;
	scanf("%d", &n);
	hanoi(n, 'A', 'B', 'C');
	return 0;
}

四.总结

很多人不理解汉诺塔可能是因为它不是像求阶乘这样的有明确的式子,比较抽象。其实函数递归就是写出过程,就是要完成的目标,加上终止条件,组成一个函数即可。如果函数递归不太理解可以多耍点函数递归的题目,慢慢的就理解函数递归的本质了。

文章到这里就结束了,创造不易,如果喜欢的话点个关注,点个赞^-^

谢谢大家^_^

你可能感兴趣的:(c语言,开发语言)