递归是许多经典算法的backbone, 是一种常用的高效的编程策略。简单的几行代码就能把一团遭的问题迎刃而解。这篇博客主要通过解决汉诺塔问题来理解递归的精髓。
汉诺塔问题简介:
在印度,有这么一个古老的传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片,1. 一次只移动一片; 2. 不管在哪根针上,小片必在大片上面。当所有的金片都从梵天穿好的那根针上移到另外一概针上时,世界就将在一声霹雳中消灭,梵塔、庙宇和众生都将同归于尽。

我们首先假设要把n个金片从宝针‘A’移动宝针‘B’,还有有另外一根'V'可以借用。
 
如果n = 1,那么直接从 A->B 即可。
如果n = 2,那么先把A最上面(第一个)金片移动到V,暂且放一下,然后第二个金片移动到B目的地,接着再把V上面的移动到B目的地,所以移动的次序是 A->V,  A->B,  V-B。
如果n = 3,可以这么考虑: 先不看出发地A最下面一个最大的金片,先解决怎么把上面两个移走,方法我们已经知道了,但是移到哪里呢?只有B, V可选,B肯定是不行,因为B是目的地,那么只能是通过B先把两个金片移动到V(A->B, A->V, B->V),然后最下面那个最大的金片移动到目的地B(A->B)。注意这时B上面仅有这个最大的金片,A上面空的,V上面有两个金片。接着把V上面两个金片借由A移动到B(V->A, V->B, A->B)。
如果n = 4, 同样的不考虑最大的一个,先把前三个移动到V,使用上面介绍的移动次序。
以此类推(其实 n = 2时,也可以看作是先解决最上面一个的问题,然后才是把最下面的金片移动到目的地)
通过分析,发现解决n个金片的方法是先借由B,把n-1个移动到V,然后把A最下面一个移动到B,在然后借由A把V上面n-1移动到B。
用java实现如下

// in java
public class Hanoi{
private static int count = 0;
public static void move(char src, char des, int n){
System.out.println("plate:"+ src +" pillar"+"->"+des+" pillar");
count++; } public static void hanoiSolver(char src, char via, char des, int n){
if (n==1){
move(src, des, n);
} else{
hanoiSolver(src, des, via, n-1);
move(src, des, n);
hanoiSolver(via, src, des, n-1);
}
} public static void main(String[] args) {
char src = 'A'; //source pillar
char des = 'B'; //detination pillar
char via = 'V'; //via pillar
int n = 3;// the numer of plates
hanoiSolver(src, via, des, n);
System.out.println("the total number of moves is "+count);
}
}
 
仔细分析这个算法,可以学习到:
1. 初中高中大学数学解题中常常用到的归纳总结。一个看似复杂至极的问题,先心里不要慌,初步分析前面几个,看到规律,推而广之。
2. 计算过程中的调用自身函数,形成重入,并因此而把复杂问题化解为相对简单或已经知道答案的小问题。这也不经我想到解数列题的各种方法。(对不起,高中是博主学习数学最认真的时候)
3. 在递归中必须有明确递归结束条件称递归出口,否则就是死循环啦。如本问题中当n=1时,就是退出递归的时候。
故事中所说的如果成功得把金片移动结束,世界就灰飞烟灭,这是真的吗?我们来小研究下:
假设f(n)为n个盘子要移动的次数。
那么根据上面分析 f(n + 1) = f(n) + 1 +f(n) = 2*f(n)+1
变换为  [f(n + 1) + 1] = 2*[f(n) + 1], 经典等比数列
因为f(1) = 1,所以可得f(n) = 2^n - 1。
f(64)= 2^64-1,
所以一共要移动 2^64-1次, 假使一秒钟移动一次,不吃不睡觉,一共要移动2.1350398e+14天,584,942,417,355年。
Take-away Tip:
递归Recursive 就是在程序中调用自身,形成重入,把复杂问题层层简化成一个已然解决的问题,
并在一定条件下退出递归。

Conquer and Divide经典例子之汉诺塔问题的更多相关文章

  1. Conquer and Divide经典例子之Strassen算法解决大型矩阵的相乘

    在通过汉诺塔问题理解递归的精髓中我讲解了怎么把一个复杂的问题一步步recursively划分了成简单显而易见的小问题.其实这个解决问题的思路就是算法中常用的divide and conquer, 这篇 ...

  2. JS经典面试题汉诺塔

    我爱撸码,撸码使我感到快乐!大家好我是Counter.今天给大家分享的是利用JS将汉诺塔原理实现出来,其实主要是考察一个递归的思想,复杂的问题简单化,汉诺塔应该都知道吧,具体的游戏规则,可以百度查查, ...

  3. 从"汉诺塔"经典递归到JS递归函数

    前言 参考<JavaScript语言精粹> 递归是一种强大的编程技术,他把一个问题分解为一组相似的子问题,每一问题都用一个寻常解去解决.递归函数就是会直接或者间接调用自身的一种函数,一般来 ...

  4. 汉诺塔hanoi

    问题描述: 有一个梵塔,塔内有三个座A.B.C,A座上有诺干个盘子,盘子大小不等,大的在下,小的在上(如图). 把这些个盘子从A座移到C座,中间可以借用B座但每次只能允许移动一个盘子,并且在移动过程中 ...

  5. 汉诺塔问题深度剖析(python实现)

    当我们学习一门编程语言的时候,都会遇到递归函数这个问题.而学习递归的一个经典案例就是汉诺塔问题.通过这篇文章,观察移动三个盘子和四个盘子的详细过程,您不仅可以深刻的了解递归,也更加熟悉了汉诺塔的游戏的 ...

  6. JAVA递归算法及经典递归例子 对于这个汉诺塔问题

    前言:递归(recursion):递归满足2个条件 1)有反复执行的过程(调用自身) 2)有跳出反复执行过程的条件(递归出口) 第一题:汉诺塔 对于这个汉诺塔问题,在写递归时,我们只需要确定两个条件: ...

  7. 化繁为简 经典的汉诺塔递归问题 in Java

    问题描述   在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针.印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔.不论白天黑 ...

  8. js 递归 汉诺塔的例子

    程序调用自身的编程技巧称为递归. //汉诺塔的游戏,n为圆盘编号数量,编号,a,b,c代表的是三个柱子 var hanio=function(n,a,b,c){     if(n>0){    ...

  9. 四柱加强版汉诺塔HanoiTower----是甜蜜还是烦恼

    我想很多人第一次学习递归的时候,老师或者书本上可能会举汉诺塔的例子. 但是今天,我们讨论的重点不是简单的汉诺塔算法,而是三柱汉诺塔的延伸.先来看看经典的三柱汉诺塔. 一.三柱汉诺塔(Hanoi_Thr ...

随机推荐

  1. GIS项目中数据开源、工具开源、开发开源的解决方案

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 摆脱免费地图开发包的约束,拒绝商业地图软件的费用,高效.精确.完备是我 ...

  2. 【JUC】JDK1.8源码分析之SynchronousQueue(九)

    一.前言 本篇是在分析Executors源码时,发现JUC集合框架中的一个重要类没有分析,SynchronousQueue,该类在线程池中的作用是非常明显的,所以很有必要单独拿出来分析一番,这对于之后 ...

  3. 微信公众账号 token 验证失败 解决办法

    问题:微信公众账号 开发过程中配置  token 提示 验证失败 如下图: 点击修改配置: 填写相关url与token(自定义):点击提交,会出现 出现这种情况,主要是对相关参数不熟悉,要了解url与 ...

  4. JQuery文件上传插件ajaxFileUpload在Asp.net MVC中的使用

    0 ajaxFileUpload简介 ajaxFileUpload插件是一个非常简单的基于Jquery的异步上传文件的插件,使用过程中发现很多与这个同名的,基于原始版本基础之上修改过的插件,文件版本比 ...

  5. 【转】浅谈MVC与三层架构

    首先给大家引入下MVC的概念: MVC(Model View Controller)模型.视图以及控制器,它是一种较为广泛应用的结构设计模式. 模型:就是在MVC设计模式中需要被显示的数据.在通常情况 ...

  6. Oracle 英文 非标准格式 日期 格式化

    最近在处理一张表的时候,需要按照日期排序,日期字段中日期的格式有两种. 格式一:07-Aug-2015 格式二:10/28/16 日期转化及格式化sql语句: select to_date('07-A ...

  7. java堆和栈的区别

    java 的内存分为两类,一类是栈内存,一类是堆内存.栈内存是指程序进入一个方法时,会为这个方法单独分配一块私属存储空间,用于存储这个方法内部的局部变量,当这个方法结束时,分配给这个方法的栈会释放,这 ...

  8. PHP 检测机器人,屏蔽内页

    PHP 检测机器人,屏蔽内页 <?php // SpiderHelper::rewrite301(); // SpiderHelper::showRobotTxt(); class Spider ...

  9. MySQL中索引和优化的用法总结

    1.什么是数据库中的索引?索引有什么作用? 引入索引的目的是为了加快查询速度.如果数据量很大,大的查询要从硬盘加载数据到内存当中. 2.InnoDB中的索引原理是怎么样的? InnoDB是Mysql的 ...

  10. 【工业串口和网络软件通讯平台(SuperIO)教程】七.二次开发服务驱动

    SuperIO相关资料下载:http://pan.baidu.com/s/1pJ7lZWf 1.1    服务接口的作用 围绕着设备驱动模块采集的数据,根据需求提供多种应用服务,例如:数据上传服务.数 ...