版权声明:本文为CSDN博主「漂流的云」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37873310/article/details/80461767

汉诺塔:汉诺塔(Tower of Hanoi)源于印度传说中,大梵天创造世界时造了三根金钢石柱子,其中一根柱子自底向上叠着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
–引用维基百科

单看这个问题描述有点让人抓瞎,这是当然,无论多么简单的问题描述,在没有建立具体地模型之前都是让人不知所云的,仅仅用生活中的语言去描述一些数学或算法问题往往会让听者产生理解偏差,这也和每个的理解能力和思维方式有很大关系,这就显示出数学的强大了,数学让问题不再模糊,参数和公式组成的模型让问题不再有理解偏差和误区,只可惜数学没学好,看来以后还得回来把高数、概率论这些给补回来。

说了一些题外话,下面来对汉诺塔问题进行解释和建立模型


这是示意图,a是起始柱,c是目标柱,b起到中转作用

在进行转移操作时,都必须确保大盘在小盘下面,且每次只能移动一个圆盘,最终c柱上有所有的盘子且也是从上到下按从小到大的顺序。

很多时候看到这些蛋疼和矫情操作就觉得数学家真是思维清奇、智慧如海,嗯还有吃饱了撑的,某兄台邪魅地一笑,道:直接把c和a交换位置不就行了,我想这位兄台以后或成大器或被人打死。

问题看起来并不复杂,当a柱子上只有一个盘子时只要把那个盘子直接移到c就行了,

有两个盘子的话把1号盘先移到b柱,在把2号盘移到c柱,最后把b柱上的1号盘移到c柱就行了,

但现在我们要移动的是64个盘子,要是我们自己手动操作,那画面会很美,闲着无聊的人可以试试,推荐去网上找找汉诺塔的小游戏,这也可以帮你加深对这个问题的理解。

下面我用图来描述64个盘子的转移流程

这里我们先把上方的63个盘子看成整体,这下就等于只有两个盘子,自然很容易了,我们只要完成两个盘子的转移就行了,好了现在我们先不管第64个盘子,假设a柱只有63个盘子,与之前一样的解决方式,前62个盘子先完成移动目标。

嗯,就这样一步步向前找到可以直接移动的盘子,62,61,60,......,2,1,最终,最上方的盘子是可以直接移动到c柱的,那就好办了,我们的2号盘也能完成向c柱的转移,这时c柱上时已经转移成功的2个盘,于是3号盘也可以了,一直到第64号盘。

下面是我用C#实现的代码:

using System;
using System.Collections.Generic;
 
namespace 汉诺塔问题_递归解决
{
   
    class Program
    {       
        static void Main(string[] args)
        {
            HanNuo(64, 'a', 'b', 'c');
 
            Console.ReadKey();
        }
 
        /// <summary>
        /// 汉诺塔问题解决方法
        /// </summary>
        /// <param name="n">汉诺塔的层数</param>
        /// <param name="a">承载最初圆盘的柱子</param>
        /// <param name="b">起到中转作用的柱子</param>
        /// <param name="c">移动到的目标柱子</param>
        static void HanNuo(int n, char a, char b, char c)
        {
            if (n == 1)   //这也是递归的终止条件
            {
                Console.WriteLine("将盘子[{0}]从 {1} -----> {2}", n, a, c); //控制台输出每次操作盘子的动向
            }
            else
            {
                HanNuo(n - 1, a, c, b);      //将a柱子上的从上到下n-1个盘移到b柱子上
                Console.WriteLine("将盘子[{0}]从 {1} -----> {2}", n, a, c);
                HanNuo(n - 1, b, a, c);      //将b柱子上的n-1个盘子移到c柱子上
            }
        }
    }
}
  代码很简洁,可能对于递归不是很理解的同学觉得有些吃力,下面我来具体解释下递归的流程。
   当n=64时,前63个要想办法成功移动到b柱上,64号是Boss,他不管上面的63个小弟用什么办法,我可以先等着,前面63个小弟可以利用我的c柱,于是64号在等着上面63号完成移到b柱,现在63是临时老大,他也想去c柱,于是他命令前62号移到b柱,他等着,62号也采取之前两个的做法,于是这个命令一直往前传,没办法,上面被压着自己也没法动啊。

    终于到了1号,他是现在唯一能动的,于是1号移动到了b柱,好了,2号可以到c柱,2第一个到目的地,心里十分激动,我都到c柱,舒服。不过当他看到a柱上的3号时,猛然一惊,我还有个上司,好吧得完成任务啊,于是让1号移到c柱,3号可以到b柱了,之后1号和2号在想办法到b柱,于是1,2,3号在b柱,4号一看很满意,但我得到b柱啊,嗯,1,2,3号你们按照刚才的办法到c柱,空出b柱给我。唉,接着折腾,后面的5号一直到63号都是这么折腾的,终于前63号移动到b柱,64号直接跑到了c柱,他觉得这些小弟办事效率真不行,不过他还是招呼小弟到c柱。

 于是剩下在b柱的63个小弟还要再干一遍他们在a柱上干的事,这里来看,1号操作的频率是最高的,而64号只要移动一次就行了,要是在现实中让人这么去干,估计早就被逼疯了。

  如果真要解释代码的每一步执行过程,那会很乱,两层递归,最后自己也会被绕的晕头转向,这个时候只要理解递归最终的解决的问题是什么就行了,中间的事交给程序,递归可以很绕也可以很直接,我们按照最直接的理解就行了。

最后关于递归算法,这中解决问题的方法也只有计算机才喜欢,我们虽然看着代码很简单,但真要深入理解也是很费脑细胞的,不过递归确实有中数学上的简洁美和逻辑美。