汉诺塔递归算法理解及实现

来源:互联网 发布:mac pro安装windows10 编辑:程序博客网 时间:2024/05/18 09:49

汉诺塔问题描述: A、B、C 三个桌子,其中A桌子上放了几个大小不同的盘子,盘子的排列顺序为: 从上到下,依次从小到大递增;现要求把这些盘子从 A 桌子上移动到 C 桌子上,盘子移动时有一点要求:每次移动必须保证三张桌子上大盘子在下、小盘子在上;打印移动次序。

如 A 上一张 盘子时,移动顺序: A -> C

代码实现:

#include <iostream>using namespace std;/***汉诺塔问题: 将 A 上所有的盘子,移动到 C 上 ,A B C*/void moveAC(char A,char C){    cout<<A<<"->"<<C<<endl;}void recursion_hano(int n,char A,char B,char C){    //递归的终止条件    if(n==1)    {        moveAC(A,C);        return;    }    //先将 A 上上边n-1个盘子移动到 B上    recursion_hano(n-1,A,C,B);  // 将 上 n-1 个圆盘移动到 B上    moveAC(A,C);    //将最大的圆盘移动到 C上    recursion_hano(n-1,B,A,C);  //将B上的圆盘移动到C上}int main(){    cout << "Hello world!" << endl;    recursion_hano(4,'A','B','C');    return 0;}


算法理解:

理解1:

宏观上我们可以这样理解:要将A上的n个盘子按照要求移动到C上,我们可以想到:先将上边的 n-1 个盘子移动到B上,再将A上剩余的最大的盘子移动到C上,然后将B上所有的盘子移动到C上,这是比较简单的理解,但是对于算法实现的过程,还是没有弄透彻。

理解2:

我们知道当盘子数为n时,移动的次数应该为 2^n-1;这个有公式  H(n) = 2H(n-1) +1 得来,理解为:上边的n-1个盘子先翻转到B上,将最大的盘子移动到C上,花费1步,然后将B上的盘子翻转到C上,花费2H(n-1)步。

后来美国的一位学者发现一种出人意料的简单的算法,只要轮流两步操作既可以实现:首先,把三张桌子按顺序首尾相接的排列,形成一个环,然后对A上的盘子开始移动,顺时针摆放成 A B C的顺序:

若n为奇数,圆盘的移动顺序是 A->C->B->A->C->B->A......... 即 间隔两个步长移动  。此处的n代表盘子位的层数,比如说 3 层汉诺塔就是从下往上数第1、3 个盘子移动的顺序。

若n为偶数,圆盘移动的顺序为A->B->C->A->B->C->A..........即 间隔一个步长移动。对n的解释同上 第二个盘子移动 A->B->C。


现在开始算法:

首先先找到能够移动的 即 A的最上边的那个盘子 如代码:

recursion_hano(n-1,A,C,B); 
该调用从下往上数层数,第一次调用时是第二层的移动 应该为: A->B

第二次调用时为第三层的移动,经过两次调用B、C翻转,应该为 :A->C

........................

     如此到最高层来移动第一个盘子

接下来:

A上的盘子移动过之后,我们要移动B、C上的盘子,移动策略同上

第二段代码的理解为:

 moveAC(A,C); 
对塔顶的两个盘子,最上层的盘子假如移动到了C上,下一层的盘子就移动到B上,因为第一段代码调用一次,B、C的顺序翻转一次。

最后一段代码的理解:

recursion_hano(n-1,B,A,C);
交换B、A的顺序是为了将 B上的盘子移动到C上,此处相当于为了实现步长为 1 的移动。

按照这样的理解,可非常清楚的了解递归每一步实现的是什么

如3阶汉诺塔的移动:A→C,A→B,C→B,A→C,B→A,B→C,A→C


原创粉丝点击