递归是许多经典算法的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. 高版本->低版本迁移,低版本客户端连接高版本数据库EXP导出报错EXP-00008,ORA-01455,EXP-00000

    生产环境: 源数据库:RHEL + Oracle 11.2.0.3 目标数据库:HP-UX + Oracle 10.2.0.4   需求:迁移部分表  11.2.0.3-->10.2.0.4,若 ...

  2. Android监听系统短信数据库变化-提取短信内容

    由于监听系统短信广播受到权限的限制,所以很多手机可能使用这种方式没法监听广播,从而没办法获取到系统短信,所以又重新开辟一条路. Android监听系统短信数据库内容变化使用场景: 1.监听短信数据库的 ...

  3. 移动开发viewport

    三种 viewport layout viewport:文档流的 css 宽度,是一个静态的值,使用 document.documentElement.clientWidth 获取,在meta中是 w ...

  4. Vue.js说说组件

    什么是组件:组件是Vue.js最强大的功能之一.组件可以扩展HTML元素,封装可重用的代码.在较高层面上,组件是自定义的元素,Vue.js的编译器为它添加特殊功能.在有些情况下,组件也可以是原生HTM ...

  5. 关于zigbee 网络拓扑节点数量的一点说明

    理论上,一个zigbee网络可以存在65535个节点,即一个协调器下挂这么多个节点(ZR & ZE),但是实际应用中几乎是不可能达到的,达到100~200已经是很不错了,达到300几乎也是凤毛 ...

  6. HttpClient通过Post上传多个文件

    public static String sendFilesPost(String url, String fileNames) { HttpClient httpClient = null; Htt ...

  7. json-lib的使用《二》

    上篇文章主要集中在了使用json-lib来实现JSON字符串和java中的对象的互转上,忽视了json-lib本身的功能,json-lib中有两个类比较重要:JSONObject和JSONArray, ...

  8. Combobox的使用

    第一次写博客,只是对自己在工作中遇到的问题进行一次总结回顾,为以后有同样的错误有一个参考: 由于最近空余时间很少,只是零零散散的把平时记录的笔记搬到博客园而已,博客中可能出现一些低级错误,希望互相学习 ...

  9. 变通实现微服务的per request以提高IO效率(三)

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  10. SQLServer清空日志

      USE [master]  GO  ALTER DATABASE TRAVEL SET RECOVERY SIMPLE WITH NO_WAIT  GO  ALTER DATABASE TRAVE ...