Tower of Hanoi

本文最后更新于 2026年3月5日 晚上

Hanoi汉诺塔问题

引入

汉诺塔是我们已经再熟悉不过的东西了,其游戏的规则是有a,b,c三个杆子,同时在a上有n个盘子,我们需要通过移动将所有盘子都移动至c杆,但移动的过程中每次只能移动一个盘子,且大盘子不能在小盘子上。

解析

我们如果需要对这个题编写程序可以采用递归的思想,将这个大问题分解成一步一步的小问题,例如现在所有盘子都在a上,我们可以把最大的盘子上面的n-1个盘子先移动到b这个空盘上,然后将最大的盘子移动到c这个目标杆上,对于剩下的n-1个盘子亦是如此。每次我们先借用辅助盘将最大盘上面的所有盘子移动到辅助盘,然后将最大盘再移动到目标盘,以此分解问题,以此我们可以写出程序的主要函数,如下所示:

1
2
3
4
5
6
7
8
9
10
11
void hanoi(int n,int a,int b,int c)
{
if(n==1)
{
cout<<"a->c"<<endl;
}
else
hanoi(n-1,a,c,b);
move(a,b);
hanoi(n-1,b,a,c);
}

对于上述程序我们来分析一下时间复杂度,其中move函数的时间复杂度可以记为常数,几乎不耗时,故该函数时间复杂度主要由两个递归函数hanoi决定,则 ,按照规律递推下去可知该函数时间复杂度为

拓展

我们发现最终如果要实现汉诺塔这个盘子的移动最终需要这么多步,而这正好是我们n个位数的二进制数能表示的所有情况,那么我们想象能不能把两者进行联系呢。显然这是可以的,我们首先将二进制数从小到大排好,例如,然后将这些盘子按照大小从小到大标号,从1开始,并将盘子与二进制的位数关联,标号越小位数越低,例如标号为1的盘子则代表最右边的位数,后我们将二进制数与前一个数比较,若是某位从0变为了1那么就将该位代表的盘子向左移动到最近的可行的柱子,接下来我们将通过三个盘子汉诺塔为例子展示这个思想,如下表:

二进制数 移动 状态
000 初始状态
001
010
011
100
101
110
111

此用二进制表示汉诺塔移动方式给我们提供了新的思路,此发现实为巧妙,小编第一次了解时大受震撼。


Tower of Hanoi
https://blog.dukechen.top/posts/tower-of-hanoi/
作者
DukeChen
发布于
2026年3月5日
更新于
2026年3月5日
许可协议