c语言带你看懂汉诺塔逻辑和代码(超详细)

汉诺塔c语言代码:

void move(char start, char end)
{
	printf("%c->%c ", start, end);
}
void Hanoi(int n, char start, char temp, char end)
{
	if (n == 1)
	{
		move(start, end);
	}
	else
	{
		Hanoi(n - 1, start, end, temp);
		move(start, end);
		Hanoi(n - 1, temp, start, end);
	}
}
int main()
{	Hanoi(4, 'A', 'B', 'C');
	return 0;
}

逻辑:

首先看汉诺塔的逻辑,假如我们一共有5个盘子:

  • 首先我们要将5个盘子移动到C上,则先将1~4盘子移到B上,再将5移到C上。
  • 要将1~4盘子移到B上,则先将1~3盘子移到C上,再将4移到B上。
  • 要将1~3盘子移到C上,则先将1~2盘子移到B上,再将3移到C上。
  • 要将1~2盘子移到B上,则先将1号盘子移到C上,再将3移到B上。
  • 如何将1盘子移到C上?只剩一个盘子时,直接移动。


第一次输出:A->C
  1. 第一步将1移到C上,只有一个盘子直接移动:A->C


第二次输出:A->B
第三次输出:C->B

2.将1、2移动到B上,则先将A上的2挪到B上,再将C上的1挪到B上:A->B  C->B.


第四次输出:A->C

3.将1、2、3移动到C上,则先将A-3移到C上。输出A->C:

再将B上的1、2移动到C上,B为起始柱子,C为终点柱子,借助A,将1,2移到C上。

则先将B-1移到A上,再将B-2移到C上:

第五次输出:B->A
第六次输出:B->C

这时再将A-1放到C上,我们就完成了将1、2、3这三个盘子放到C上。

第七次输出:A->C


4.将1、2、3、4移动到B上。

对于A-4,只有一个盘,直接移动。

第八次输出:A->B

此时要将C-1、2、3移动到B上:

(1)要将C-1、2、3给B,得先将C-1、2给A。

(2)要将C-1、2给A,得先将C-1给B。

(2-1)先将C-1给B

第九次输出:C->B

(2-2)为了将1、2都放到A上,此时C-2移到A上,再将B-1移到A上:

第十次输出:C->A
第十一次输出:B->A

(1-1)此时,我们已经将1、2挪给了A,这时将C-3放到B上。

第十二次输出:C->B

再将A-1、2以C为中转柱移给B:

即A-1挪给C:

第十三次输出:A->C

再将A-2挪给B

第十四次输出:A->B

再将C上的1挪给B

第十五次输出:C->B


5.将1、2、3、4、5都移到C上。

此时我们已经完成了将1、2、3、4都移动到B上。

现在,我们将5号盘移到C上:

第十六次输出:A->C

此时我们要将B-1、2、3、4都移到C上。

(I)要将B-1、2、3、4都移到C上,则先将B-1、2、3移到A上

    (1)要将B-1、2、3都移到A上,则先将B-1、2先移到C上

    (2)要将B-1、2都移到C上,则先将B-1先移到A上

结果:

第十七次输出:B->A     1
第十八次输出:B->C     2
第十九次输出:A->C     1
第二十次输出:B->A      3
第二十一次输出:C->B   1
第二十二次输出:C->A    2
第二十三次输出:B->A    1

(II)此时将B-4放到C上:

第二十四次输出:B->C     4

此时我们已经将1、2、3移到了A上。这时我们想将A-1、2、3都移到C上,则B作为中转柱子。

(1)若要将A-1、2、3都移到C上,则先将A-1、2挪到B上。

(2)要将A-1、2都挪到B上,则先将A-1挪到C上。

此过程跟上面一样,这里不再继续叙述。

第二十五次输出:A->C     1
第二十六次输出:A->B      2
第二十七次输出:C->B      1

此时1、2盘都在B上

第二十八次输出:A->C     3

这里将3号盘子放到C上

第二十九次输出:B->A     1
第三十次输出:   B->C      2
第三十一次输出: A->C     1


汉诺塔逻辑概括

至此,汉诺塔移动盘子的逻辑我们已经讲述清楚了。

概括以下就是:

一、

假设A有n个盘子要移到C,则将n-1个盘子先移到B,再将最底下那个(n)号盘子移给C。

如何将A上n-1个盘子移动给B呢?

则先将上面n-2个盘子先移给C,再将最底下那个(n-1)号盘子移动给B。

如何将A上n-2个盘子移动给C呢?

则先将上面n-3个盘子移动给B,再将最底下那个(n-2)号盘子移动给C。

......

依次类推

直到剩下最顶上一个盘子,就可以直接移动。


代码输出对照

此时我们来对照以下代码的运行输出和我们的假设输出是否相同:

代码如下:

void move(char start, char end)
{
	printf("%c->%c \n", start, end);
}

void Hanoi(int n, char start, char temp, char end)
{
	if (n == 1)
	{
		move(start, end);
	}
	else
	{
		Hanoi(n - 1, start, end, temp);
		move(start, end);
		Hanoi(n - 1, temp, start, end);
	}
}
int main()
{	Hanoi(5, 'A', 'B', 'C');
	return 0;
}

运行结果如下:


程序逻辑

现在我们再来看看程序的运行逻辑,为了方便讲述,我们假设有3个盘子。

首先我们在main函数中向Hanoi函数传入参数,即盘子个数,以及三个柱子:


int main()
{	Hanoi(3, 'A', 'B', 'C');
	return 0;
}

我们将A柱子作为start开始柱,将B柱子作为temp中转柱子,将C柱子作为end终点柱子。

void Hanoi(int n, char start, char temp, char end)
{
	if (n == 1)
	{
		move(start, end);
	}
	else
	{
		Hanoi(n - 1, start, end, temp);
		move(start, end);
		Hanoi(n - 1, temp, start, end);
	}

要将1、2、3这三个盘子放到C中,首先1、2要放入B中。而若要将A-1、2放入B中,就要将C作为中转柱。

第一次输出为A->C  1
第二次输出为A->B  2
第三次输出为C->B  1

此时B就成为了终点柱子,C成为了中转柱子。

也就是下图的黄色语句:

执行完黄色语句后,汉诺塔变成下面这样:

此时A只剩下一个盘子,执行第一条Hanoi语句下面的move函数调用语句,将A上的3号盘子移动到B上:

第四次输出为A->C   3

此时,我要将tempB上的n-1(2)个盘子放到C上,我就要借助A柱子,先将n-2个盘子放到A上。

此时B成了开始start柱,A成了我们的中转柱子,而C是我们的目标柱子。

来到第三条语句:

此处这条语句的四个参数分别是(2,B,A,C)

传入后,B为开始start柱,A为temp柱,C为end柱。n>1,进入else部分:

来到第一条语句Hanoi(n-1,start,end,temp),此时的参数为(1,B,C,A)。

由这条语句进入Hanoi函数后,B为开始start,C为中转temp,A为结束end。

此时来到if语句,n==1,进入move函数,B将1号盘子传给了A:

第五次输出B->A.

此时我们从第一条Hanoi函数语句出来,走到move函数语句。此时B还是start柱,A变回了temp柱,C变回了end柱。

此时我们来到move(start,end)语句。

这里就是将2号盘子放到C上。

第六次输出B->C.

接下来来到第三条语句:

这时这条语句的参数是(1,A,B,C)

这条语句执行,我们再进入Hanoi函数:

此时原先为temp的A变成了start,原先为start的B变为了temp。

此时n==1,进入if语句。

进入if语句后,执行move(start,end)。

即将A也就是start柱子上的1号盘,传给作为end的C柱。

第七次输出A->C.

至此,我们将全部的盘子都移动到了C上。


输出对照

这里我们检验我们逻辑的输出和程序的输出:


程序概括:

程序代码作用概括:

第一条hanoi语句的作用是将A上的n-1个盘子移到B中。

第二条语句move语句的作用是将A上最大的盘子即n号盘移到C中。

第三条语句Hanoi语句的作用是,将B看作开始start柱子,A为辅助temp柱子,而C为终点end柱子。




以上是作者对汉诺塔这一经典小游戏的全部思路和看法,若有错误或者不足之处,欢迎您在评论区下面留下你的宝贵意见!

如果这篇文章有帮助到你,请留下你的点赞收藏评论+关注,这将对我产生极大的动力!学海无涯,我与你共勉!




评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值