C语言 用递归思想 解决汉诺塔问题

文章目录


前言

汉诺塔问题

汉诺塔(Tower of Hanoi)问题源于印度传说。话说大梵天创造世界时造了三根金钢石柱子(假设为A、B、C),其中一根柱子(假设为A)自底向上叠着64片大小不同的黄金圆盘。有一天,大梵天命令婆罗门把圆盘从A柱移动C柱上。并且规定,在柱子间移动圆盘时,每次只能移动一个圆盘,且任何时候大圆盘不能放在小圆盘上。

并给出算法代码,打印出来移动顺序。 

一、算法分析

 要把64个盘子从A座移动到C座,需要移动大约2的64次方盘子。一般人是不可能直接确定怎样移动盘子的每一个具体步骤。假如,有一个人想:如果有第二个人能有办法将上面63个盘子从A座移动到另外一座,第一个人再将最后一个盘子移动到C座,再命令第二个人将63个盘子从B座移动到C座,至此任务就完成了。

但是,有一个问题实际尚未解决,第二个人怎么样将63个盘子从A座移动到B座? 为了解决将63个盘子从A座移动到B座,第二个人又想,如果有人能够将62个盘子从一座移动到另外一座,就可以将63个盘子从A座移动到C座,他是这么做的:

(1)命令第三个人将62个盘子从A座移动到C座;

(2)自己将1个盘子从A座移动到B座;

(3)再命令第三人将62个盘子从C座移动到B座。

这样,还是有一问题还没有解决,怎样将62个盘子移动到C座?

 这就需要运用递归思想:

递归(Recursion),指在函数的定义中使用函数自身的方法,即程序的自身调用,常用于描述以自相似方法重复事物的过程。但是,使用递归思想,必须有限制条件,在这个题中,递归结束的条件是 最后一个人只须移动一个盘子,否则递归还需要继续进行。

必须说明,只有当第64个人的任务完成后,第63个人的任务才能完成,所以,只有当2-64个人任务完成后,第一个人任务才能完成(每个人完成任务都必须完成一次递归)。因为第二步只需移动一个盘子,可以直接实现,但是第(1),(3)步并不是能够直接完成。

第(1)步又可用递归方法分解为:

1,将A座上1个盘子从A座移动到C座;

2,将A座上1个盘子从A座移动到B座;

3,将C座上一个盘子从C座移动到B座。

第(3)步也可用递归方法分解为:

1,将B座上1个盘子从B座移动到A座上;

2,将B座上1个盘子从B座移动到C座上;

3,再将A座上1个盘子从A座移动到C座上。

所以,可以直观的看出来,在一次递归调用中,又富含两个小递归,才能完成一次真正的递归。

如图所示:

 将以上总和起来,可以得到移动3个盘子的步骤为:

A->C,A->B,C->B,A->C,B->A,B->C,A->C

以上盘子的移动顺序,为每一次递归,需完成的。

因此,由上面的分析可知:将n个盘子从A座移动到C座可以分解为三个步骤:

(1)将A座上n-1个盘子借助C座先移动到B座上;

(2)把A座上剩下的一个盘子移动到C座上;

(3)将n-1个盘子从B座上借助A座移动到C座上。 

因此,可以把上面三个步骤分成两类操作:

(1)(n>1)时,将n-1个盘子移动到另外一个座上,这一步是最重要的一步,里面包含 3个步骤,方可完成,这是一个递归的过程,即将每个人的任务层层下方,知道第64个人为止。

(2)将1个盘子从一个座上移动到另一个座上。

二、

1.编写程序整体思想

用两类函数实现以上两类操作,用Father函数实现上面第一类操作用  Father(n,one,two,three)

表示将n个盘子从one 座移动到 three座的过程 需借助two座。

用 move函数(x,y)表示最终结果的输出,即将一个盘子从一个座上移动到另外一个座上。

可以分析出,最终将一个盘子移动,完成递归,只能从A座移动到C座上,这就为程序提供了很大的方便。

2.程序

#include<stdio.h>
  void Father(int n,char one,char two,char three)
  {
  	void move(char x,char y);		//调用move函数	
		if(n==1)
		  move(one,three);  //将n==1作为限制条件
		else
		{
			Father(n-1,one,three,two);//当n>=2时,步骤1,先把最上面的一大堆n-1个小盘子从A移动到B
        move(one,three);//此时A上就剩下第你n个大盘子,只需要从A移动到C
        Father(n-1,two,one,three);//此时需要将B上的n-1个小盘子从B移动到C

	
				  }		  

				}
    void move(char x,char y)		//定义move函数			
	{
		printf("%c-->%c\n",x,y);  //打印输出顺序 
		
		
				}			

 int main()
 {
	int m;
   printf("请输入总共的盘子数");
   scanf("%d",&m);
	
   Father(m,'A','B','C');
  
    return 0;	
                 }

下面 我们输入 3,会出现以下结果:


总结

以上对递归函数作了比较详细的介绍,与应用,并根据汉诺塔问题,进行了分析,和编写相应程序,对递归的巧妙应用,简单化的解决了复杂问题。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值