汉诺塔问题描述: A、B、C 三个桌子,其中A桌子上放了几个大小不同的盘子,盘子的排列顺序为: 从上到下,依次从小到大递增;现要求把这些盘子从 A 桌子上移动到 C 桌子上,盘子移动时有一点要求:每次移动必须保证三张桌子上大盘子在下、小盘子在上;打印移动次序。
如 A 上一张 盘子时,移动顺序: A -> C
代码实现:
- <span style="font-size:14px;">#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); <span> </span>//将最大的圆盘移动到 C上
- recursion_hano(n-1,B,A,C); //将B上的圆盘移动到C上
- }
- int main()
- {
- cout << "Hello world!" << endl;
- recursion_hano(4,'A','B','C');
- return 0;
- }
- </span>
理解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的最上边的那个盘子 如代码:
- <span style="font-size:14px;">recursion_hano(n-1,A,C,B); </span>
第二次调用时为第三层的移动,经过两次调用B、C翻转,应该为 :A->C
........................
如此到最高层来移动第一个盘子
接下来:
A上的盘子移动过之后,我们要移动B、C上的盘子,移动策略同上
第二段代码的理解为:
- <span style="font-size:14px;"> moveAC(A,C); </span>
最后一段代码的理解:
- <span style="font-size:14px;">recursion_hano(n-1,B,A,C);</span>
按照这样的理解,可非常清楚的了解递归每一步实现的是什么
如3阶汉诺塔的移动:A→C,A→B,C→B,A→C,B→A,B→C,A→C