简介

关于Hanoi塔问题的分析,在网上的文章都写烂了。之所以打算写这篇文章,更多的是针对这个问题相关的各种数学思路和代码实现过程做一个总结。它虽然是一个看似简单的问题,后面引申出来的问题推导方法和思路还是比较丰富的。

问题描述

这个问题起源于一个类似传说故事,在Hanoi这个地方有一个寺庙,这里有3根柱子和64个大小不同的金碟子。每个碟子有一个孔可以穿过。所有的碟子都放在第一个柱子上,而且按照从上到下碟子的大小依次增大的顺序摆设。如下图:

现在,假定寺庙里的僧侣要移动这些碟子,将它们从最左边移动到最右边的柱子上。不过移动的规则如下:

1. 每次只能从一个柱子的最上面移动一个碟子到另外一个柱子上。

2. 不能将大碟子放到小碟子的上面。

按照前面这个规则,我们该怎么去移动这些碟子呢?假定单位时间内可以移动一片碟子,那么最终移动这些碟子到目的柱子需要多长的时间呢?

问题分析

在分析这个问题的时候,我们可以先从一些简单的场景来看怎么来移动碟子保证可以达到目的。假定我们有3个碟子,那么移动它们的过程如下图:

我们假定柱子从左到右分别为a, b, c。从前面移动碟子的步骤可以看到,我们要将a上面的两个碟子先移动到中间的b柱子作为过渡,然后再将最下面的柱子移动到目的c柱子,然后再将上面的两个碟子移过来。在将最下面的碟子移动到c之前,首先的步骤1, 2, 3是将上面的碟子移动到柱子b。而将最下面碟子移动后,上面的两个碟子又要移动一遍,不过是从b移动到c,只是借助的柱子不一样。

所以,从上面的过程,我们可以看到一个可以递归解决问题的思路,如下图:

如图所示,首先我们针对有n个碟子的柱子a,将n-1个碟子移动到柱子b。假定这个问题为S(n)表示移动的步数,则上面的问题是S(n)的一个子问题S(n-1)。这一步对应步骤1。然后将最下面的碟子移动到柱子c,最后再将n-1个碟子移动到c。后面这一步也相当于S(n)的子问题S(n-1)。对应步骤3.它和前面第一步移动n-1个碟子唯一不同的地方在于第一步是借助c将n-1个碟子从a移动到b,而最后这一步是借助a将n-1个碟子从b移动到c。除了借助的柱子和目的柱子不一样,其他的都是一样的。

这样我们就可以很容易得到一个这样的推导关系:

S(n) = 2S(n - 1) +1

再考虑一种初始的情况,假定只有一个碟子需要移动,我们直接将碟子从a移动到c,那么需要的步骤是1步。因此可以说S(1) = 1。

进一步推导

有了前面的归纳关系,我们可以很容易得到如下的一组推导结果:

S(1) = 1

S(2) = 2 x S(1) + 1 = 2 + 1 = 3

S(3) = 2 x S(2) + 1 = 2 x 3 + 1 = 7

S(4) = 2 x S(3) +1 = 2 x 7 + 1 = 15

从这些得出来的结果里,似乎还看不到多少有规律的地方。不过我们可以采取一种根据递推原则代换的方式来尝试发现规律。前面的推导关系里有S(n) = 2 x S(n - 1) +1,那么我们将有如下的推导:

这里,我们发现什么规律没?原来,这里似乎符合如下的一个等式:

当我们最终一路递推到T1的时候,它将满足如下的形式:

这似乎是我们所求得的结果了。当然,这种推导也有可能会出错。最好的情况是我们还需要验证一下它。验证的方法可以考虑用数学归纳法。因为过程比较简单,这里就不再赘述了。最终可以验证出来结果是满足以上等式的。从前面的推导我们可以看出,最终要实现将64个碟子移动到目的柱子,需要的时间是2的64次方这个量级的。在一定程度上,用计算机的内置数据类型都没法表示这个数值。

代码实现

前面的分析可以发现,从计算机实现来说,这个问题是指数函数级别的,意味着它的增长速度非常快,在一定程度上计算机都无法解决。在一个比较小的数值范围内,我们还是可以做一个参考实现的。有了前面的讨论,我们的完整代码实现如下:

 1 public class Hanoi {
 2
 3     public static void move(char a, char b, char c, int n) {
 4         if(n == 0)
 5             return;
 6         move(a, c, b, n-1);
 7         System.out.printf("Move disk %d from %s to %s\n", n, a, c);
 8         move(b, c, a, n-1);
 9     }
10
11     public static void main(String[] args) {
12         move('a', 'b', 'c', 3);
13     }
14 }  

这部分代码里,我们递归的退出条件是当最终碟子移走,即n == 0。运行这一段程序的结果如下:

Java代码  
  1. Move disk 1 from a to c
  2. Move disk 2 from a to b
  3. Move disk 1 from c to a
  4. Move disk 3 from a to c
  5. Move disk 1 from b to c
  6. Move disk 2 from b to a
  7. Move disk 1 from c to b

和前面图示的过程是完全一致的。当然,在提供的数值比较大的时候,我们这种递归的方式就溢出了。

总结

Hanoi塔问题是一个经典的递归问题,它本身的数学复杂度达到了指数函数级别。所以使得运算时间的增长非常快。通过一种递归的思路,首先我们可以总结出一个问题的递归描述方式。然后我们再通过不断的代入和分析,去发现形成等式的规律。这是一种发现递归问题等式描述的方法。为了保证方法最终的正确性,我们还需要经常使用数学归纳法来证明这个等式的正确性。

这部分代码里,我们递归的退出条件是当最终碟子移走,即n == 0。运行这一段程序的结果如下:

Java代码  
  1. Move disk 1 from a to c
  2. Move disk 2 from a to b
  3. Move disk 1 from c to a
  4. Move disk 3 from a to c
  5. Move disk 1 from b to c
  6. Move disk 2 from b to a
  7. Move disk 1 from c to b

和前面图示的过程是完全一致的。当然,在提供的数值比较大的时候,我们这种递归的方式就溢出了。

总结

Hanoi塔问题是一个经典的递归问题,它本身的数学复杂度达到了指数函数级别。所以使得运算时间的增长非常快。通过一种递归的思路,首先我们可以总结出一个问题的递归描述方式。然后我们再通过不断的代入和分析,去发现形成等式的规律。这是一种发现递归问题等式描述的方法。为了保证方法最终的正确性,我们还需要经常使用数学归纳法来证明这个等式的正确性。

Hanoi塔问题分析相关推荐

  1. n阶Hanoi塔问题(动图分析)-C语言

    n阶Hanoi塔问题 Hanoi塔问题规则 Hanoi塔分析 参考程序 Hanoi塔问题规则 每次只能移动一个圆盘: 圆盘可以插在X.Y和Z中的任一塔座上: 任何时刻都不能将一个较大的圆盘压在较小的圆 ...

  2. 小知识系列(3):Hanoi塔(汉诺塔,河内塔)

    同样,借此来强化学习,但是说实话我写这个感觉很玄.Hanoi塔是昨天刚学到的东西,想了很久,感觉还是没有悟透,可能学到更多新东西,或产生了新的想法,或突然悟到了什么,届时会再做修改. 看了很多关于Ha ...

  3. 1.2 Hanoi塔问题

    1.2 Hanoi塔问题 问题描述 分析 代码 总结 问题描述 Hanoi塔问题由3个竖立着的塔座和一组中间有孔的圆盘组成,圆盘中间有个孔以便沿塔座柱移动叠放,每个圆盘有不同的直径.Hanoi塔的初始 ...

  4. 递归---Hanoi塔问题

    http://shmilyaw-hotmail-com.iteye.com/blog/2077098 简介 关于Hanoi塔问题的分析,在网上的文章都写烂了.之所以打算写这篇文章,更多的是针对这个问题 ...

  5. 分治法——Hanoi塔

    1.Hanoi塔算法的基本原理: (1)问题描述: 有n个不同大小的盘子和三根木柱A, B, C,一开始,所有的盘子按照上小下大的顺序套在A柱上,要把n个盘子移到C柱上,一次只能移动一个盘子,且不允许 ...

  6. Hanoi塔(分治法的应用)

    1.分治法 分治法的设计思想是将一个难以直接解决的大问题分解成一些规模较小的相同问题,以便各个击破,分而治之. 一般来说,分治算法在每一层递归上都有3个步骤: (1)分解:将问题分解成一系列子问题. ...

  7. 二 用标准c语言实现hanoi塔问题,天大2016年1二月《数据结构》期末大作业考核要求.doc...

    数据结构要求:独立完成,作答时要按照模版信息填写完整,写明题型.题号:作答方式:手写作答或电脑录入,使用学院统一模版(模版详见附件):提交方式:以下两种方式任选其一,手写作答的同学可以将作业以图片形式 ...

  8. Hanoi塔(汉诺塔/梵天塔)问题

    Hanoi塔 汉诺塔(梵天塔/Hanoi)问题是计算机中比较典型的一个递归问题.废话不多说了,直接上代码. Python3.5代码 """重温本科学习过之书籍:计算机科学 ...

  9. hanoi塔问题解析(一) c++实现

    什么是hanoi塔? 汉诺塔问题:古代有一个梵塔,塔内有三个座A.B.C,A座上有64个盘子,盘子大小不等,大的在下,小的在上.有一个和尚想把这64个盘子从A座移到B座,但每次只能允许移动一个盘子,并 ...

最新文章

  1. PHP5 $this self parent static的区别
  2. 【内有网易黑猪肉券福利】网易MCTalk首秀——在线教育是一场马拉松
  3. windows和linux互传文件,用户配置文件和密码配置文件,用户和组管理
  4. (一)加法计算器(第一个iOS APP)
  5. python n个list如何组成矩阵_有序矩阵中第K小的元素amp;x的平方根(二分法篇)
  6. 安卓查看php文件是否存在,Android_Android编程判断SD卡是否存在及使用容量查询实现方法,本文实例讲述了Android编程判断 - phpStudy...
  7. 多个 Linux 发行版考虑移除 Chromium 软件包
  8. 官网下载keil MDK最新版本、历史版本和芯片pack包
  9. ag-grid 设置行高
  10. 在ubuntu20.04上安装最新版的qq
  11. 单机数据库的实现----------01数据库
  12. 直接学python3_初学者可以直接学Python3吗?
  13. android 找不到手机,找不到 Android 开发者选项,难道我的手机系统没有?| 有轻功 #290...
  14. 软考-高项-论文-信息系统项目的人力资源管理
  15. NVR(网络硬盘录像机)以及其他相近名词DVR、DVS、NVS
  16. docker学习笔记(10):docker迁移与升级等其它操作
  17. 自然语言处理NLP 2022年最新综述:An introduction to Deep Learning in Natural Language Processing
  18. 二叉树的前中后序遍历(栈)(C++)
  19. java 金额千位用逗号隔开_金额格式化 处理千分位 金额逗号,隔开
  20. 共射放大电路以及三极管三种接法的判断--共基?共集?共射?

热门文章

  1. Android payload注入
  2. 因赵丽颖结婚,微博工程师受到的高并发挑战
  3. python爬虫自学网站_python爬虫学习 爬取幽默笑话网站
  4. 计算机怎么我游戏怎么玩,我的电脑总是玩游戏卡怎么处理
  5. LSTM解决梯度消失问题
  6. 「前端-HTML」 HTML-表格-表单-第二篇
  7. K8S安装Jumpserver
  8. iview-admin使用Iconfont-阿里巴巴矢量图标库的时候,多个Iconfont合并如何使用
  9. 什么是双眼皮修复原则
  10. 基于ijkplayer 0.8.8编译的完整so. libijkffmpeg.so等,支持ssl h265, rm, rmvb