043. 使用递归解决汉诺塔问题

汉诺塔问题是一个经典的递归问题。它的规则如下:有三根柱子(通常标记为 A、B 和 C),在 A 柱上有若干个大小不一的盘子,盘子的大小从上到下依次增大。目标是将所有盘子从 A 柱移动到 C 柱,过程中可以借助 B 柱作为辅助,但必须满足以下规则:

  1. 每次只能移动一个盘子。
  2. 每次移动时,只能将一个盘子从顶部移动到另一根柱子的顶部。
  3. 任何时候,在三根柱子的任何一根上,较大的盘子不能放在较小的盘子上面。

解题思路

汉诺塔问题可以通过递归方法解决。递归的核心思想是将问题分解为更小的子问题:

  1. 将 n−1 个盘子从 A 柱移动到 B 柱(借助 C 柱)。
  2. 将第 n 个盘子(最大的盘子)从 A 柱直接移动到 C 柱。
  3. 再将 n−1 个盘子从 B 柱移动到 C 柱(借助 A 柱)。

C语言实现

以下是使用递归解决汉诺塔问题的完整代码:

#include <stdio.h>

// 定义递归函数解决汉诺塔问题
void hanoi(int n, char fromPeg, char toPeg, char auxPeg) {
    if (n == 1) { // 递归终止条件:只有一个盘子时直接移动
        printf("将盘子 1 从 %c 移动到 %c\n", fromPeg, toPeg);
        return;
    }

    // 将 n-1 个盘子从 fromPeg 移动到 auxPeg,借助 toPeg
    hanoi(n - 1, fromPeg, auxPeg, toPeg);

    // 将第 n 个盘子从 fromPeg 移动到 toPeg
    printf("将盘子 %d 从 %c 移动到 %c\n", n, fromPeg, toPeg);

    // 将 n-1 个盘子从 auxPeg 移动到 toPeg,借助 fromPeg
    hanoi(n - 1, auxPeg, toPeg, fromPeg);
}

int main() {
    int n;
    printf("请输入盘子的数量:");
    scanf("%d", &n);

    if (n <= 0) {
        printf("盘子数量必须是正整数!\n");
        return 1;
    }

    // 调用汉诺塔递归函数
    hanoi(n, 'A', 'C', 'B');

    return 0;
}

代码说明

  1. 递归函数 hanoi

  2. 参数:

  3. n:当前需要移动的盘子数量。

  4. fromPeg:起始柱子。

  5. toPeg:目标柱子。

  6. auxPeg:辅助柱子。

  7. 递归终止条件:当 n == 1 时,直接将盘子从起始柱子移动到目标柱子。

  8. 递归步骤:

  9. 先将 n-1 个盘子从 fromPeg 移动到 auxPeg

  10. 将第 n 个盘子从 fromPeg 移动到 toPeg

  11. 再将 n-1 个盘子从 auxPeg 移动到 toPeg

  12. 主函数 main

  13. 提示用户输入盘子的数量。

  14. 调用 hanoi 函数,初始时从 A 柱移动到 C 柱,借助 B 柱。

示例运行

输入:

请输入盘子的数量:3

输出:

将盘子 1 从 A 移动到 C
将盘子 2 从 A 移动到 B
将盘子 1 从 C 移动到 B
将盘子 3 从 A 移动到 C
将盘子 1 从 B 移动到 A
将盘子 2 从 B 移动到 C
将盘子 1 从 A 移动到 C

注意事项

  1. 递归深度

  2. 汉诺塔问题的递归深度为 2n−1,对于较大的 n,递归调用次数会非常多,可能会导致栈溢出。在实际应用中,通常限制 n 的大小(如 n≤20)。

  3. 输出格式

  4. 输出的移动步骤清晰地展示了每一步的操作,有助于理解汉诺塔问题的解决过程。

视频讲解

BiliBili: 视睿网络-哔哩哔哩视频 (bilibili.com)