递归是许多经典算法的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. ThinkPHP学习(一)

    下载3.2框架后,解压缩到web目录下面,可以看到初始的目录结构如下: 3.2版本相比之前的版本自带了一个完整的应用目录结构和默认的应用入口文件,开发人员可以在这个基 础之上灵活调整.其中, Appl ...

  2. 浅尝ECMAScript6

    浅尝ECMAScript6 简介 ECMAScript6 是最新的ECMAScript标准,于2015年6月正式推出(所以也称为ECMAScript 2015),相比于2009年推出的es5, es6 ...

  3. 【406错误】 The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers.

    今天遇到一个奇怪的错误,关于Springmvc的,我明明在Controller方法中写了@ResponseBody,返回一个Map,结果报了406错误. 结果发现,少了一个jar包: 加上去就没事了.

  4. AJAX 详解注释很全来自互联网

    1: //用户名校验的方法 2: //这个方法使用XMLHTTPRequest对象进行AJAX的异步数据交互 3: var xmlhttp; 4: function verify(){ 5: //1. ...

  5. [Q&A] 应用程序清单生成失败

    当在 Silverlight 客户端属性里(如下图),添加"允许在浏览器外运行应用程序"和"在浏览器内运行时需要提升的信任"时, 图1 目录下会自动生成如下两个 ...

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

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

  7. 原生js文字标签云上下滚动播放

    效果:http://hovertree.com/texiao/js/25/ 效果图: 代码如下: <!DOCTYPE html> <html> <head>< ...

  8. (1-1)文件结构的升级(Area和Filter知识总结) - ASP.NET从MVC5升级到MVC6

    ASP.NET从MVC5升级到MVC6 总目录 MVC5项目结构 带有Areas和Filter的项目结构 一般来说,小的MVC项目是不考虑领域的,但是,如果是稍微复杂一点的项目,往往是需要领域这个概念 ...

  9. super.getClass()方法调用

    下面程序的输出结果是多少?import java.util.Date;public class Test extends Date{public static void main(String[] a ...

  10. svg.js教程及使用手册详解(一)

    做毕设的时候,因为要使用到画图和自定义动画,所以接触到了SVG.网上关于SVG和Canvas的对比很多,具体的辨析这里就不赘言.网上关于SVG的所谓教程基本上都是SVG本身,但是却没有一个针对svg. ...