递归是许多经典算法的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. Kooboo CMS - 之后台注册用户流程方法。

    今天决定写一篇好一点的文章,吼吼!首先我们必须找到这个文件,这个文件是UsersController.cs,我们找到和添加新用户有关的方法,如下代码: public virtual ActionRes ...

  2. T-SQL CROSS APPLY、MERGE

    写在前面 刚才看项目里一个存储过程,也是好长时间没有使用Sql Server2008了,好多写法和函数感觉到陌生,这就遇到了CROSS APPLY 和MERGE的语法,两者之前完全没接触过. 所以专门 ...

  3. 非对称技术栈实现AES加密解密

    非对称技术栈实现AES加密解密 正如前面的一篇文章所述,https协议的SSL层是实现在传输层之上,应用层之下,也就是说在应用层上看到的请求还是明码的,对于某些场景下要求这些http请求参数是非可读的 ...

  4. easyui combotree的使用

    前台HTML: <div class="search-container"> <table class="search-container-table& ...

  5. Web 组合查询加 分页

    使用ADO.NET 数据访问技术制作web端组合查询加分页的功能关键在于查询SQL语句的拼接 以Car 表为例 每页显示3条数据 数据访问类使用查询方法,tsql 查询的连接字符串,查询的参数放到Ha ...

  6. CodeFirst时使用T4模板(你肯定没用过的笨方法,还望园友指教)

    我们都知道T4模板用于生成相似代码. 在DBFirst和ModelFirst条件下我们很容易从.edmx下获取所有实体类和其名称,并且通过我们定义的模板和某些遍历工作为我们生成所需要的相似代码. 但是 ...

  7. 从零开始学 Java - 利用 Nginx 负载均衡实现 Web 服务器更新不影响访问

    还记得那些美妙的夜晚吗 你洗洗打算看一个小电影就睡了,这个时候突然想起来今天晚上是服务器更新的日子,你要在凌晨时分去把最新的代码更新到服务器,以保证明天大家一觉醒来打开网站,发现昨天的 Bug 都不见 ...

  8. java web学习总结(十八) -------------------过滤器的高级使用

    在filter中可以得到代表用户请求和响应的request.response对象,因此在编程中可以使用Decorator(装饰器)模式对request.response对象进行包装,再把包装对象传给目 ...

  9. 软件公司为何要放弃MongoDB?

    本文转至:http://database.51cto.com/art/201503/469510_all.htm(只作转载, 不代表本站和博主同意文中观点或证实文中信息) Olery成立于2010年, ...

  10. 悟透JavaScript(理解JS面向对象的好文章)

    引子 编程世界里只存在两种基本元素,一个是数据,一个是代码.编程世界就是在数据和代码千丝万缕的纠缠中呈现出无限的生机和活力. 数据天生就是文静的,总想保持自己固有的本色:而代码却天生活泼,总想改变这个 ...