汉诺塔的图解递归算法

汉诺塔的图解递归算法参考原文链接 1 http www cnblogs com dmego p 5965835 html2 https blog csdn net xb2355404 article details 79144451 一 起源 汉诺塔 又称河内塔 问题是源于印度一个古老传说的益智玩具 大梵天创造世界的时候做了三根金刚石柱子 在一根

一.起源:

  汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。

二.抽象为数学问题:

  如下图所示,从左到右有A、B、C三根柱子,其中A柱子上面有从小叠到大的n个圆盘,现要求将A柱子上的圆盘移到C柱子上去,期间只有一个原则:一次只能移到一个盘子且大盘子不能在小盘子上面,求移动的步骤和移动的次数

汉诺塔的图解递归算法

解:(1)n == 1

             第1次  1号盘  A—->C       sum = 1 次

       (2)  n == 2

             第1次  1号盘  A—->B

             第2次  2号盘  A—->C

             第3次  1号盘  B—->C        sum = 3 次

  (3)n == 3

        第1次  1号盘  A—->C

        第2次  2号盘  A—->B

        第3次  1号盘  C—->B

        第4次  3号盘  A—->C

        第5次  1号盘  B—->A

        第6次  2号盘  B—->C

        第7次  1号盘  A—->C        sum = 7 次

 

不难发现规律:1个圆盘的次数 2的1次方减1

       2个圆盘的次数 2的2次方减1

                         3个圆盘的次数 2的3次方减1

                         。  。   。    。   。 

                         n个圆盘的次数 2的n次方减1

 故:移动次数为:2^n – 1

三.算法分析(递归算法):

       我们在利用计算机求汉诺塔问题时,必不可少的一步是对整个实现求解进行算法分析。到目前为止,求解汉诺塔问题最简单的算法还是同过递归来求。

       实现这个算法可以简单分为三个步骤:

    (1)     把n-1个盘子由A 移到 B;

    (2)     把第n个盘子由 A移到 C;

    (3)     把n-1个盘子由B 移到 C;

从这里入手,在加上上面数学问题解法的分析,我们不难发现,移到的步数必定为奇数步:

    (1)中间的一步是把最大的一个盘子由A移到C上去;

    (2)中间一步之上可以看成把A上n-1个盘子通过借助辅助塔(C塔)移到了B上,

    (3)中间一步之下可以看成把B上n-1个盘子通过借助辅助塔(A塔)移到了C上;

public class Hanoilmpl { public static void hanoi(int n, char A, char B, char C) { if (n == 1) { move(A, C); } else { hanoi(n - 1, A, C, B);//将n-1个盘子由A经过C移动到B move(A, C); //执行最大盘子n移动 hanoi(n - 1, B, A, C);//剩下的n-1盘子,由B经过A移动到C } } private static void move(char A, char C) {//执行最大盘子n的从A-C的移动 System.out.println("move:" + A + "--->" + C); } public static void main(String[] args) { System.out.println("移动汉诺塔的步骤:"); hanoi(3, 'a', 'b', 'c'); } }

 

四.可怕的汉诺塔

汉诺塔是一个发源于印度的益智游戏,也叫河内塔。相传它源于印度神话中的大梵天创造的三个金刚柱,一根柱子上叠着上下从小到大64个黄金圆盘。大梵天命令婆罗门将这些圆盘按从小到大的顺序移动到另一根柱子上,其中大圆盘不能放在小圆盘上面。当这64个圆盘移动完的时候,世界就将毁灭。 
汉诺塔游戏 
汉诺塔问题源于印度神话 
那么好多人会问64个圆盘移动到底会花多少时间?那么古代印度距离现在已经很远,这64个圆盘还没移动完么?我们来通过计算来看看要完成这个任务到底要多少时间? 
我们首先利用数学上的数列知识来看看F(n=1)=1,F(n=2)=3,F(n=3)=7,F(n=4)=15……F(n)=2F(n-1)+1; 
我们使用数学归纳法可以得出通项式:F(n)=2^n-1。当n为64时F(n=64)=18446744073709551615。 
我们假设移动一次圆盘为一秒,那么一年为31536000秒。那么18446744073709551615/31536000约等于584942417355天,换算成年为5845.54亿年。 
目前太阳寿命约为50亿年,太阳的完整寿命大约100亿年。所以我们整个人类文明都等不到移动完整圆盘的那一天。














 20次以内秒级别的,没问题,30以上就费劲了!

五.汉诺塔问题拓展

有一个int数组arr其中只含有1、2和3,分别代表所有圆盘目前的状态,1代表左柱,2代表中柱,3代表右柱,arr[i]的值代表第i+1个圆盘的位置。比如,arr=[3,3,2,1],代表第1个圆盘在右柱上、第2个圆盘在右柱上、第3个圆盘在中柱上、第4个圆盘在左柱上。如果arr代表的状态是最优移动轨迹过程中出现的状态,返回arr这种状态是最优移动轨迹中的第几个状态。如果arr代表的状态不是最优移动轨迹过程中出现的状态,则返回-1。

给定一个int数组arr及数组的大小n,含义如题所述,请返回一个int,代表所求的结果。

解析:
1.如果当前盘子在中间,不是最优解(直观观察);

2.如果当前盘子在最右边,说明数组已经完成了Hanoi的前两步,第一步将前n-1移动到中间步数为2^(n-1)-1,然后最后一个n移动到右边步数为1,总共为2^(n-1);

 此时只需要递归判断前n-1个数组的移动次数,并且添加进来;

3.如果当前盘子最左边,说明对第n盘子没有进行任何操作(如果是最优解),只需要递归求解前n-1个盘子的操作次数

具体参见实现代码:

public int chkStep(int[] arr, int n) { if (arr == null || arr.length < 1 || arr.length != n) { return -1; } return checkstep(arr, n - 1, 1, 2, 3); } private int checkstep(int[] arr, int cur, int left, int mid, int right) { if (cur == -1) {// 所有盘子递归完毕 return 0; } if (arr[cur] == mid) {// 在中间 return -1; } else if (arr[cur] == left) {// 在左边 return checkstep(arr, cur - 1, left, right, mid); } else {// 在右边 int tmp = checkstep(arr, cur - 1, mid, left, right); if (tmp == -1) { // 如果cur-1个盘子不是最优解 return -1; } return (1 << cur) + tmp; } }

 


参考链接:1.http://www.cnblogs.com/dmego/p/5965835.html

                 2.https://blog.csdn.net/xb/article/details/

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/199352.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月26日 下午1:17
下一篇 2026年3月26日 下午1:18


相关推荐

  • Claude Code 进阶教程:详解 Skills、Subagents 与 MCP 高级用法 • Eyad

    Claude Code 进阶教程:详解 Skills、Subagents 与 MCP 高级用法 • Eyad

    2026年3月16日
    3
  • 前端实现人员关系图谱

    前端实现人员关系图谱入职前端工作到现在差不多有一年半的时间了,和朋友偶然聊天的时候被问到,能不能用所学的前端知识做一个家族关系的族谱,可以使家族关系更加简单明了。当时听完这个需求,觉得可能还是蛮简单的,后来动手做的时候,发现族谱的连线,是需要根据返回的数据动态生成的,这就是我这个小前端,有点头秃了????。解决技术困难当时阻碍我前进的就是如何实现族谱的连线以及根据数据渲染它们的对应关系,后来在逛博客的过程中,发现了antdesign的charts图表组件。利用这个组件,如果可以进行一些改造,可能就可以实现族谱的关系图。

    2022年6月26日
    43
  • Android中的PCM设备

    Android中的PCM设备Android 上的应用一般都是通过 AudioTrack 类来播放音频 通过 AudioRecord 类来录制音频 AudioTrack 类和 AudioRecord 类是 AndroidFrame 封装提供给应用使用的音频接口类 这些类经过层层的 Binder JNI 等调用后会调用 AudioHAL 层提供的相关接口 这些接口实现了对音频设备 通路等一系列操作 就这样最终完成 AndroidApp 和硬件

    2026年3月18日
    2
  • sqlserver datetime与smalldateTime

    sqlserver datetime与smalldateTimedatetime 从1753年1月1日到9999年12月31日的日期和时间数据,精确度为百分之三秒(等于3.33毫秒或0.00333秒)。–A.测试datetime精度问题DECLARE@tTABLE(datechar(21))INSERT@tSELECT’1900-1-100:00:00.000’INSERT@t

    2022年5月12日
    41
  • 【全文翻译】MixMatch: A Holistic Approach to Semi-Supervised Learning

    【全文翻译】MixMatch: A Holistic Approach to Semi-Supervised Learning全文翻译 MixMatch AHolisticApp SupervisedLe 摘要半监督学习已被证明是利用未标记数据来减轻对大型标记数据集的依赖的强大范例 在这项工作中 我们统一了当前的半监督学习主导方法 以产生一种新算法 MixMatch 该算法猜测数据增强的未标记示例的低熵标记 并使用 MixUp 混合标记和未标记的数据 MixMatch 可在许多数据集和标记的数据量上大幅度获取最新的结果 例如 在具有 250 个标签的 CIFAR 10 上 我们将错误率降低 4 倍

    2026年3月17日
    2
  • php 0xffffffff,[已解决]怎么随机出0xFF000000 – 0xFFFFFFFF 之间的数?

    php 0xffffffff,[已解决]怎么随机出0xFF000000 – 0xFFFFFFFF 之间的数?importwin.ui;importgdip;//导入GDI+库importmath;/*DSG{{*/varwinform=..win.form(bottom=399;parent=…;right=599;text=”aardioForm”)winform.add(button={bottom=363;text=”button”;left=423;top=318;z=1…

    2022年5月17日
    43

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号