C++ 递归经典案例:汉诺塔问题详解
问题描述
汉诺塔(Tower of Hanoi)是递归算法的经典入门题。规则如下:
- 有三根柱子,分别记为 A、B、C。
- A 柱上有 n 个大小不同的圆盘,从小到大叠放。
- 目标是将所有盘子从 A 移动到 C。
- 移动过程中,大盘子不能压在小盘子上面。
- 每次只能移动一个盘子。
题目链接:面试题 08.06. 汉诺塔问题 - LeetCode
解题思路
面对这个问题,直接思考如何一次性移动 n 个盘子会非常复杂。作为工程师,我们习惯将大问题拆解为小问题。这里的核心思想是分治法配合递归。
假设我们要把 n 个盘子从 A 移到 C,借助 B:
- 第一步:先把 A 上面的 n-1 个盘子看作一个整体,借助 C 移动到 B 上。此时 A 只剩下最大的那个盘子,B 上有 n-1 个小盘子。
- 第二步:将 A 中剩下的最大盘子直接移动到 C 上。这是合法的,因为 C 是空的或者上面只有比它大的盘子(实际上此时 C 是空的)。
- 第三步:现在问题变成了把 B 上的 n-1 个盘子移动到 C 上,借助 A。这完全重复了第一步的逻辑,只是起始和终点变了。
当 n=1 时,不需要拆分,直接从源柱子移到目标柱子即可。这就是递归的终止条件。
关键点说明
- 辅助柱子的角色:在递归过程中,辅助柱子(B)的角色是动态变化的。第一次调用时它是中间站,第二次调用时它变成了起点。代码中通过参数传递来体现这种变化。
- 状态转移:
dfs(A, C, B, n-1)表示把 A 的 n-1 个移到 B(C 作辅助),dfs(B, A, C, n-1)表示把 B 的 n-1 个移到 C(A 作辅助)。注意参数的顺序变化。
参考实现
下面是基于 C++ STL vector 的实现,模拟栈的操作。
#include <vector>
using namespace std;
class Solution {
public:
// 深度优先搜索,负责具体的移动逻辑
void dfs(vector<int>& A, vector<int>& B, vector<int>& C, int n) {
// 递归终止条件:只剩一个盘子,直接移动
if (n == 1) {
C.push_back(A.back());
A.();
;
}
(A, C, B, n - );
C.(A.());
A.();
(B, A, C, n - );
}
{
n = A.();
(A, B, C, n);
}
};


