最近在学习C语言的递归时,遇到了书上(C语言程序设计(第4版)-谭浩强著)的一个例子(例7.4),苦思冥想好几天终于是整明白了,这个问题就是标题所提到的Hanoi(汉诺)塔问题:
汉诺塔问题是一个经典的递归问题,其目标是将一堆盘子从一个柱子上按照规定的顺序移动到另一个柱子上,中间可以借助第三个柱子进行中转。具体来说,汉诺塔问题规定了以下几个条件:
- 有三根柱子,分别称为A、B和C。
- 初始时,所有的盘子都放在柱子A上,从上到下依次递减大小,最大的盘子在底部。
- 目标是将所有的盘子从柱子A移动到柱子C,要求在移动过程中始终保持盘子的大小顺序不变,即较大的盘子不能放在较小的盘子上。
- 可以借助柱子B作为中转,但每次只能移动一个盘子,且只能将盘子放在空柱子或者放在比自己大的盘子上。
汉诺塔问题的解决方案可以通过递归算法来实现,其基本思路如下:
- 如果只有一个盘子,直接将其从柱子A移动到柱子C。
- 如果有多个盘子,可以将其分成三个步骤:
- 将除了最大的盘子外的其他盘子从柱子A移动到柱子B,借助柱子C作为中转。
- 将最大的盘子从柱子A移动到柱子C。
- 将之前移动到柱子B上的盘子从柱子B移动到柱子C,借助柱子A作为中转。
通过递归地应用上述步骤,可以将任意数量的盘子从柱子A移动到柱子C,并且保持大小顺序不变。汉诺塔问题是一个经典的递归案例,展示了递归算法的应用和思维方式。
下面主要是分析运行的流程,希望能帮助像我一样的小伙伴们更快地掌握递归,和理解解决此问题的思想。
废话不多说先看代码:
#include <stdio.h>
void move(char a, char b);
void hanoi(int n, char x, char y, char z);
int main()
{
int m;
printf("Input the number of dishes:");
scanf("%d", &m);
printf("The step to moving %d dishes:\n", m);
hanoi(m, 'A', 'B', 'C');
return 0;
}
void hanoi(int n, char x, char y, char z)
{
if(n == 1)
move(x, z);
else
{
hanoi(n - 1, x, z, y);
move(x, z);
hanoi(n - 1, y, x, z);
}
}
void move(char a, char b)
{
printf("%c-->%c\n", a, b);
}
这是ChatGPT给的解释:
当 n = 3 时,按照给出的代码,汉诺塔问题的运行流程如下:
- 调用 hanoi(3, 'A', 'B', 'C')。
- 进入 else 分支。
- 第一次递归调用 hanoi(2, 'A', 'C', 'B')。
- 再次进入 else 分支。
- 第一次递归调用 hanoi(1, 'A', 'B', 'C')。
- n = 1,执行 move('A', 'C'),输出 A-->C。
- 执行 move('A', 'B'),输出 A-->B。
- 第二次递归调用 hanoi(1, 'C', 'A', 'B')。
- n = 1,执行 move('C', 'B'),输出 C-->B。
- 执行 move('A', 'C'),输出 A-->C。
- 第三次递归调用 hanoi(2, 'B', 'A', 'C')。
- 再次进入 else 分支。
- 第一次递归调用 hanoi(1, 'B', 'C', 'A')。
- n = 1,执行 move('B', 'A'),输出 B-->A。
- 执行 move('B', 'C'),输出 B-->C。
- 第二次递归调用 hanoi(1, 'A', 'B', 'C')。
- n = 1,执行 move('A', 'C'),输出 A-->C。
因此,当 n = 3 时,输出的结果为: A-->C A-->B C-->B A-->C B-->A B-->C A-->C
这是将三个盘子从柱子 A 移动到柱子 C 的汉诺塔问题的解决方案。
以下是我写在纸上的分析过程,方便加深理解: