汉诺塔递归解决方法经典分析

一位法国数学家曾编写过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。

虽然这只是一个传说,但也给我们提出了一个问题,今天在学python的时候刚好看到一道题目,使用递归解决这个问题,打印出有4个金片的移动过程。我一开始没有注意到题目要求是每次移动一片而且每一个柱子上的金片都要是从小到大排的,还以为很简单,后来发现,实现起来是很麻烦的,令人头疼。

我在网上看了好多对这个问题的解决方法,都是使用递归,但是分析的都很欠缺,导致我一个人考虑了一大早上,直至头痛,大概总结如下:

假设三根石针分别为a,b,c,金片一开始放在a上,我们的目的是把金片按照从小到大的顺序放到c上。

我们从最简单的情况分析,只有一片的话,直接放到c上,这种不必多说了吧。

如果有两片的话,步骤应该是这样的:a->b,a->c,b->c,这里箭头代表每次拿最上面的一片移动到另一根石针上面。可以看到我们如果用c语言写的话应该是:move(2,a,c,b);move(2,a,b,c)move(2,b,a,c);2代表a上有两个金片,(2,a,c,b)代表把a顶上的一个先移动到b上,以此类推;我们每次把移动的步骤打印出来,就可以写出来下面这样的递归:

void move(int n, char a, char b, char c)
{
    if (n == 1)
        printf("\t%c->%c\n", a, c);
    else
    {
        move(n - 1, a, c, b);
        printf("\t%c->%c\n", a, c);
        move(n - 1, b, a, c);
    }
}  

但是当我依照这个步骤去想如果a上面放更多的金片的时候,这个步骤因为太麻烦了,我不能推出来,所以也不能验证它的正确性,只知道这是根据递归写出来的。因为它真的很麻烦我不相信那个人可以推出来5以上的步骤,如果可以,我认为他是天才。但是这个问题本身就是这么麻烦,用递归解决的话对某些人来说才是更容易理解的。

下面我推一下当n=3的时候的执行步骤:

因为步骤实在比较多,所以上面的过程图越画越乱,在这里我大概讲述一下,大家看红色的线条,是我一开始的执行路径,刚进这个函数的时候,参数是(3,a,b,c),然后在对函数进行调用,但这一次我们传进来的是(2,a,c,b),因为2还是不等于1,所以再进行调用,这次穿进去的则是(1,a,b,c),这里比较难理解,因为我们可以看到这里的参数顺序不停发生改变,我们可以看我们的函数内部, move(n - 1, a, c, b);    move(n - 1, b, a, c);   这两句话都把传进来的参数顺序改变了,至于为什么要这么做,就是我们一开始分析只有两个金片的时候交换的那样,只要你在理解的时候不要被形参(a,b,c)的顺序和我们实际传进来的顺序搞混还是很好理解的。绿色框内的输出就是打印到屏幕上的步骤,褐色的线条是每层递归执行完的返回,当我们返回到第一次进入的递归的内部,又到了move(n - 1, b, a, c)这个函数的递归了,是我图上的橙色线条部分,因为后面的步骤和前面的差不多而且空间有限我就没有再进行分析了,你们可以自己画这样的图帮助分析。

上图是我运行程序的结果,可以看到和我分析的前四个输出是一样的,我在程序中加了计数,算出总共移动了7次;

 1
 2 void move(int n, char a, char b, char c)
 3 {
 4     if (n == 1)
 5         printf("\t%c->%c\n", a, c);
 6     else
 7     {
 8         move(n - 1, a, c, b);
 9         printf("\t%c->%c\n", a, c);
10         move(n - 1, b, a, c);
11     }
12 }
13
14 int main()
15 {
16     int n;
17     printf("请输入要移动的块数:");
18     scanf_s("%d", &n);
19     move(n, ‘a‘, ‘b‘, ‘c‘);
20     return 0;
21 } 
时间: 2024-08-07 00:13:11

汉诺塔递归解决方法经典分析的相关文章

汉诺塔-递归

有三根柱子A,B,C A柱子上穿着N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小.要将所有圆盘移至C柱子,遵循以下规则: 1. 每次只能移动一个圆盘: 2. 小的上面不能放大的. 拆解问题,N个盘子,把最下面的那个大的看做地面,看成不存在,问题变为N-1汉诺塔问题 把下面两层看做不存在,就是N-2.... 方法就是: 先移动一个盘子(解决1汉诺塔问题) 在此基础上,解决2汉诺塔问题 .... .... 解决N-1汉诺塔问题 最终解决N汉诺塔问题 当然,递归是倒过来的,虽然思维是倒过来的,但实际

数据结构--汉诺塔递归Java实现

1 /*汉诺塔递归 2 * 1.将编号0-N-1个圆盘,从A塔座移动到B上面 3 * 2.将编号N的1个圆盘,从A移动到C上面 4 * 3.最后将B上面的N-1个圆盘移动到C上面 5 * 注意:盘子的编号从上到下1-N 6 * */ 7 public class HannoTower_Recursion { 8 9 public static void main(String[] args) { 10 int nDisk = 3; 11 doTowers(nDisk,'A','B','C');

经典汉诺塔递归实现

/*  * 为了将num个盘子从char移动到to,需要先将第num个盘子上面的num-1个盘子移动到temp上,  * 然后将第num个盘子移动到to上,最后将第N-1个盘子从temp移动到to上.这样通过递归  * 就可以实现汉诺塔问题的求解.  */ public static void HanuoTower(int num, char from, char temp, char to){ if(num==1){ System.out.println("从"+from+"

汉诺塔递归

#一日一词# 今天在学习Python的时候,遇到了递归问题,案例呢就是经典的汉诺塔游戏,表示虽然以前就接触过这游戏,解起来也很容易,不过放在编程里,几行的代码可够我手推了一个多小时.╭∩╮(︶︿︶)╭∩╮ 当然也是感受到了搞清楚一个(我认为的)难题的乐趣,心情大好,买条裤子. (表示从晚上一直整理到第二天,电脑没电所以今早发,生日与学习紧密结合)? 首先说下汉诺塔游戏,如下图,需要利用中间的柱子将左边的所有圆盘移动到最右边的柱子上,且和原来的大小上下顺序一致,移动过程中保证大盘永远在小盘下面.

汉诺塔递归实现

经典问题汉诺塔的实现中,递归实现可以说是代码量最少,并最简单易懂的实现方法了. 假设有三根柱子a,b,c.其中a柱子上有n个金片.我们的目的就是把n个金片借助b,全部移动到c上.这是一个汉诺塔问题. 这个问题可以分解成如下子问题: (1)将n-1个金片从a移动到b.这又是一个汉诺塔问题. (2)上面执行完之后,可以直接将第n个金片移动到c. (3)上面两步执行完之后,将n-1个金片从b移动到c.这又再次是一个汉诺塔问题. 很显然,把上面的步骤翻译成递归形式可以得到如下的程序: 1 #includ

汉诺塔递归思维

汉诺塔比较经典的实现是利用递归,但也可以利用堆栈. 题意理解:有A,B,C三个柱子,将A柱子上的N个盘子(从大到小排列)移到C柱子上,每次只允许移动一个盘子,并且保证每个柱子上的盘子的排列都是从大到小. 1.递归实现 假设只有一个盘子,那么只需实现 A->C 这个动作: 如果有两个盘子,那么需要 (1)A->B; (2)A->C; (3)B->C; 如果有三个盘子,可以将前两个盘子看作一个盘子,对两个盘子重复以上三个步骤,于是得到N个盘子的递归算法,递归结束的条件是N=1: 1 v

汉诺塔递归思考

汉诺塔:问题描述:ABC三根柱子(注解:即 source,other,dest),从A盘将一摞盘子(N个)移到C盘,每次只能动一个盘子,并保证小盘子必须在大盘子上面,N=1 A-CN=2 A-B A-C B-CN=3 A-C A-B C-B A-C B-A B-C A-C...N=N.. 盘子编号:1 ,2 ,3.......N这里要用到两个函数: public static void move(int n, int source, int dest) 将第N个盘子从source移到dest m

汉诺塔递归问题

算法: 当只有一个盘子的时候,只需要从将A塔上的一个盘子移到C塔上. 当A塔上有两个盘子是,先将A塔上的1号盘子(编号从上到下)移动到B塔上,再将A塔上的2号盘子移动的C塔上,最后将B塔上的小盘子移动到C塔上. 当A塔上有3个盘子时,先将A塔上编号1至2的盘子(共2个)移动到B塔上(需借助C塔),然后将A塔上的3号最大的盘子移动到C塔,最后将B塔上的两个盘子借助A塔移动到C塔上. 当A塔上有n个盘子是,先将A塔上编号1至n-1的盘子(共n-1个)移动到B塔上(借助C塔),然后将A塔上最大的n号盘

汉诺塔-递归实现

#include<stdio.h> void move(char x,char y) { printf("%c->%c\n",x,y); } //将n个盘子从1中借助2移动到3 void hanoi(int n,char one,char two,char three) { if(n==1) move(one,three); else { hanoi(n-1,one,two,three); move(one,three); hanoi(n-1,two,one,thre