汉诺塔
汉诺塔(Tower of Hanoi),又称河内塔,是一个源于印度古老传说的益智玩具。
大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序
摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另
一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动
一个圆盘。
-----摘自百度百科
什么是递归
序调用自身的编程技巧称为递归( Pecursion )。递归做为一种算法在程序设计
语言中广泛应用。一个过程或函数在其定义或说明中有直接或间接调用自身的一
种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小
的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复
计算,大大地减少了程序的代码量。递归的主要思考方式在于:把大事化小
递归的两种必要条件
·存在限制条件,当满足这个限制条件的时候,递归便不再继续。
·每次递归调用之后越来越接近这个限制条件。
汉诺塔游戏规则
游戏里有三根柱子(A柱)(B柱)(C柱),在A柱上从下往上按大小顺序排着圆盘
玩家需要做的是把圆盘从下面开始按大小顺序重新摆放在C柱上面。并且规定,在小
圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。(如图)
根据规则我们知道n为1的时候,我们只需要把A柱的圆盘移到C柱上。
但n>1时,我们需要将n-1的圆盘的圆盘移动到B柱上,在将A柱剩余最大的一个圆盘移动到C柱上,最后将B柱上的圆盘移动到C柱上。
代码实现解决汉诺塔问题
我们先把汉诺塔所需要的值定义出来,n是圆盘,a,b,c分别对应的是三根柱子,hanoi函数实现盘子移动的过程。
int count = 0;//计数器(全局变量)
int main()
{
int n = 0;//盘子
char a = 'A';//起点柱
char b = 'B';//中间柱
char c = 'C';//终点柱
scanf("%d", &n);
hanoi(n, a, b, c);//实现盘子移动的操作过程
printf("移动%d个圆盘需要%d步\n",n,count);
return 0;
}
我们根据上面圆盘n为1图解时知道,n为1时把A柱上剩的最后一个圆盘移到C柱上,我也将此作为递归的出口,防止递归不受控制,move函数实现打印移动圆盘时的路径
void move(int n,char a, char c)
{
printf("%c-->%c\n", a, c);
count++;//每输出一次路径自增一次
}
void hanoi(int n,char a,char b,char c)
{
if (n == 1)//把盘子为1作为递归的出口
{
move(n, a, c);//剩下最后一个盘子,直接移到终点去
}
当n>1时候,我们借助C柱把A柱上n-1个圆盘移动到B柱上
else
{
hanoi(n - 1, a, c, b);//借助c柱把a柱上的n-1个盘子移到b柱上去
move(n, a, c);//把a柱上的最后一个移到c柱子上去
hanoi(n - 1, b, a, c);//借助a柱把b柱上的n-1个盘子移到c柱上去
}
}
此时A柱上就剩最后一个最大的圆盘,然后将这个圆盘移动到C柱上
然后再借助A柱把B柱上n-1个圆盘移动到C柱上,最后实现从A柱的圆盘移动到C柱去
参考代码
int count = 0;
void move(int n,char a, char c)
{
printf("%c柱上的第%d个盘子:%c-->%c\n",a,n, a, c);
count++;
}
void hanoi(int n,char a,char b,char c)
{
if (n == 1)
{
move(n, a, c);//假设最后一个盘子,直接移到终点去
}
else
{
hanoi(n - 1, a, c, b);//借助c柱把a柱上的n-1个盘子移到b柱上去
move(n, a, c);//把a柱上的最后一个移到c柱子上去
hanoi(n - 1, b, a, c);//借助a柱把b柱上的n-1个盘子移到c柱上去
}
}
int main()
{
int n = 0;//盘子
char a = 'A';//起点柱
char b = 'B';//中间柱
char c = 'C';//终点柱
scanf("%d", &n);
hanoi(n, a, b, c);//实现盘子移动的操作过程
printf("%d个盘子总共要移动:%d次",n, count);
return 0;
}