许多问题的求解过程都可以用递归分解方法描述,一个典型的例子是著名的汉诺(hanoi)塔问题。
1. 问题介绍
n 阶汉诺塔问题:假设有三个分别命名为 X、Y 和 Z 的塔座,再塔座 X 上有 n 个不同直径、编号为 1,2,...,n 的圆盘。现要求将塔座X上的 n 个圆盘移至塔座 Z 上,并仍按同样顺序叠排。
圆盘移动时必须遵循以下规则:
① 每次只能移动一个圆盘。
② 圆盘可以在 X、Y 和 Z 中的任何一个塔座上。
③ 任何时刻都不能将一个较大的圆盘压在较小的圆盘之上。
【算法思想】
① 当 n=1 时,问题比较简单,只要将编号为 1 的圆盘从塔座 X 直接移动到塔座 Z 上即可;
② 当 n>1 时,需要用塔座 Y 做辅助塔座,若能设法将压在编号为 n 的圆盘上的 n-1 个圆盘从塔座 X(依照上述原则)移至塔座 Y 上,则可先将编号为 n 的圆盘从塔座 X 移至塔座 Z上,然后再将塔座 Y 上的 n-1 个圆盘(依照上述原则)移至塔座 Z 上。
2. 代码实现
下面是使用 C 语言实现汉诺塔问题的代码,同时统计总共移动了多少次。
c
#include<stdio.h>
int count = 0;
void hanoi(int n, char from, char aux, char to) {
if (n == 1) {
printf("No.1 from %c to %c\n", from, to);
count++;
return;
}
hanoi(n - 1, from, to, aux);
printf("No.%d from %c to %c\n", n, from, to);
count++;
hanoi(n - 1, aux, from, to);
}
int main() {
int n = 0;
scanf("%d", &n);
hanoi(n, 'A', 'B', 'C');
printf("%d\n", count);
return 0;
}
第一步:移动上面 n-1 个盘子。
第二步:移动第 n 个盘子,即最大盘子。
第三步:再移动上面 n-1 个盘子。
3. 代码思路
c
void hanoi(int n, char from, char aux, char to)
c
hanoi(n, 'A', 'B', 'C');
把 n 个盘子从 A 柱子借助 B 柱子移动到 C 柱子。
4. 递归终止条件
c
if (n == 1) {
printf("No.1 from %c to %c\n", from, to);
count++;
return;
}
当只有一个盘子时,不需要再继续分解问题,直接把这个盘子从起始柱子移动到目标柱子即可。
这里的 return 非常重要。它表示当前函数执行结束,不再继续向下执行。如果没有这个 return,程序会继续调用:
c
hanoi(n - 1, from, to, aux);
5. 代码分析
在汉诺塔问题中,每输出一次:
c
printf("No.%d from %c to %c\n", n, from, to);
就表示真实移动了一次盘子。所以每打印一次移动步骤,就应该让移动次数加一:
c
count++;
递归调用本身不是一次移动,而是"一组移动过程"。
6 汉诺塔的执行过程

总结
汉诺塔问题虽然代码不长,但非常适合理解递归中的三个关键点:递归函数的含义、递归终止条件,以及递归问题如何分解为更小规模的问题。