hanoi塔(汉诺塔)–C语言
一.什么是hanoi塔
汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。
大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。
大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。
并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
即
规则:
1.每次只能移动一个圆盘;
2. 圆盘可以插在A,B,C中任意一根柱子上;
3.任何时刻都不能将较大的圆盘压在较小的圆盘上面。
n盘汉诺塔就是n个圆盘在A,B,C三个柱子上面按照上述规则进行移动。
二.hanoi塔解题思路
————当然hanoi塔的题目是一道很典型的采用递归思路来进行解决的问题;
1.问题分解
首先,我们需要将n个圆盘从柱子A移动到柱子C上面:
- 将1 ~ n-1个圆盘作为整体从A借助C移动到B上;
- 将A上的第n个圆盘从A移动到C;
- 再将B上的1 ~ n-1个圆盘整体从B借助A移动到C上。
这样问题就从移动n个圆盘简化为了移动n-1个圆盘的问题;
问题层层化简,最后就能简化成1个圆盘的移动问题。
这样就完成了hanoi塔的移动。
2.设置递归
我们由问题分解中的思路就能够得到递归;
其中递归的结束条件就是只有一个圆盘的时候,而调用就是移动n-1个圆盘的时候;
所以我们以此就能够写出递归的代码:
void hanoi(int n,char x,char y,char z)
{
if(n==1)
move(x,1,z);
//将编号为1的圆盘从x移动到z
else{
hanoi(n-1,x,z,y);
//将x上编号为1至n-1的圆盘借助z移到y
move(x,n,z);
//将编号为n的圆盘从x移到z
hanoi(n-1,y,x,z);
//将y上编号为1至n-1的圆盘借助x移到z
}
}
三.具体讲解
以三盘hanoi塔作为例子具体讲解:
1.初始状态
A | B | C | |
---|---|---|---|
第一层 | 1 | ||
第二层 | 2 | ||
第三层 | 3 |
(圆盘3最大,圆盘1最小)
要将三个圆盘从A移动到C。
2.递归
n=3 ——所以执行hanoi(n-1,x,z,y);
n=2 ——所以执行hanoi(n-1,x,z,y);
(这里的x代表柱子A,y代表柱子C,z代表柱子B,是从上面的x,z,y传递而来)
n=1 ——结束递归,将1号圆盘从A移动到C
递归工作栈的工作状态:
n值 | x值 | y值 | z值 |
---|---|---|---|
3 | A | B | C |
n值 | x值 | y值 | z值 |
---|---|---|---|
2 | A | C | B |
3 | A | B | C |
n值 | x值 | y值 | z值 |
---|---|---|---|
1 | A | B | C |
2 | A | C | B |
3 | A | B | C |
到1的时候就该move(x,1,z)
A | B | C | |
---|---|---|---|
第一层 | |||
第二层 | 2 | ||
第三层 | 3 | 1 |
同时出栈
n值 | x值 | y值 | z值 |
---|---|---|---|
2 | A | C | B |
3 | A | B | C |
然后执行move(x,n,z)
这时候栈里面是:
n值 | x值 | y值 | z值 |
---|---|---|---|
2 | A | C | B |
3 | A | B | C |
所以将二号圆盘从A移动到B
A | B | C | |
---|---|---|---|
第一层 | |||
第二层 | |||
第三层 | 3 | 2 | 1 |
接下来继续hanoi(n-1,y,x,z)
这时栈顶的n=2,所以:
n=1 ——结束递归
n值 | x值 | y值 | z值 |
---|---|---|---|
1 | C | A | B |
2 | A | C | B |
3 | A | B | C |
A | B | C | |
---|---|---|---|
第一层 | |||
第二层 | 1 | ||
第三层 | 3 | 2 |
n值 | x值 | y值 | z值 |
---|---|---|---|
2 | A | C | B |
3 | A | B | C |
依次类推,最后就会成为这样的移动方式:
四.代码
#include<stdio.h>
int num=0;
//设置一个num来记录移动的次数
void move(char a,int n,char c)
{
num++;
printf("<%d>:将%d号盘子从%c移动到%c\n"
,num,n,a,c);
}
//其实move函数就是换了一个皮的输出
//代表移动这个步骤,所以num++
void hanoi(int n,char x,char y,char z)
{
if(n==1)
move(x,1,z);
else{
hanoi(n-1,x,z,y);
move(x,n,z);
hanoi(n-1,y,x,z);
}
}
int main()
{
int n;
char a,b,c;
scanf("%d",&n);
//n个圆盘
printf("移动%d个圆盘的过程为:\n",n);
hanoi(n,'A','B','C');
//这里是n个圆盘
//和传过去的A,B,C这三个字符代表三根柱子
return 0;
}