汉诺塔是一种移动圆盘的游戏,同时也是一个简单易懂的递归算法应用示例。
游戏规则
游戏开始时如左图所示,有 3 根柱子 A、B、C,柱子 A 上有 5 个圆盘。把这 5 个圆盘按照 原本的顺序移动到柱子 C 上之后游戏就会结束。
移动圆盘时需要遵守以下两个条件。
移动条件
① 1 次只能移动 1 个圆盘。 ② 不能把大的圆盘放在小的圆盘上。
我们的目标就是在这两个条件下,通过把圆盘往 B 或 C 移动来完成游戏。
先来看看只有2个圆盘的情况吧。
小的圆盘在最顶端,所以可以把它移动到 B 上。
把大的圆盘移动到C上。
再把小圆盘往C移动,操作完毕。由于只有2 个圆盘,此时便可以确认游戏结束。
3个圆盘时又会怎样呢?我们可以忽略最大的 圆盘,先将其他的圆盘往B移动。
将其他的2个圆盘按照之前移动只有2个圆盘 时的操作移动到B。
然后把最大的圆盘移动到C
再次按照之前的操作,把B上的2个圆盘移动到 C。于是,3个圆盘的移动也完成了。实际上,不 管需要移动多少圆盘,这个游戏最终都能达成目 标。我们试着用数学归纳法来证明这个结论吧。
只有1个圆盘时,可以轻松达成目标。
假设圆盘数量为n时同样可以达成目标。
思考一下圆盘数为n+1的情况。
忽略最大的一个圆盘。
根据之前的假设,圆盘数量为n时可以达成目 标,所以先把n个圆盘移动到B。
再把最大的圆盘移动到C。
最后再把B上的n个圆盘移动到C,游戏结束。
大家可能会觉得这太简单了,但是要想移动 n 个圆盘,只需要按照移动 n -1 个圆盘 时的方法移动即可。而要移动 n -1 个圆盘,就需要按照移动 n -2 个圆盘时的方法移动。 这样追溯下去,最终就会回到移动 1 个圆盘时的操作方法上。
像这样,在算法描述中调用算法自身的方法就叫作“递归”。递归被运用到各种各 样的算法中,这些算法统称为“递归算法”。2-6 节中讲到的归并排序和 2-7 节中讲到的 快速排序便是递归算法的示例。
我们再来看一看递归算法需要的运行时间。
假设解决有 n 个圆盘的汉诺塔问题时需要的时间为 T(n)。只有 1 个圆盘时只需 1 步 就能完成,所以 T(1)=1。圆盘数为 n 时,把上面的 n-1 个圆盘从 A 移到 B 上需要 T(n-1), 再把最大的圆盘移到 C 上需要 1 步,最后把 B 上的 n -1 个圆盘移到 C 上需要 T(n -1), 因此 T(n)=2T(n-1)+1。
上面的公式即为 ,这便是解决这个问题所需要的最短时间。
《我的第一本算法书》 [日]石田保辉 宫崎修一/著 张贝/译