C语言修炼——汉罗塔问题与函数递归

一、汉罗塔问题

1.介绍

汉诺塔问题是一个经典的问题。汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把所有圆盘移到另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且一次只能搬动一个圆盘。问应该如何操作搬动次数最少?

2.讲解

假设我们有A、B、C三根石柱,其中A为起始石柱,B为中转石柱,C为目的石柱。
在这里插入图片描述
如果A上有一个圆盘,我们可以直接将A上圆盘移到C上,即A->C,共1步;
如果A上有两个圆盘,我们需要借助中转石柱,即B石柱,先将A上小圆盘移到B上,再将A上大圆盘移到C上,最后将之前移到B上的小圆盘移到C上,即A->B A->C B->C,共3步;
如果A上有三个圆盘,我们首先将小圆盘移到C上,接着中圆盘移到B后小圆盘再次移到B,然后大圆盘移到C,接着小圆盘移到A后中圆盘移到C,最后小圆盘移到C,即A->C A->B C->B A->C B->A B->C A->C,共7步。

以此类推,最小移动次数总为2^n-1(n为圆盘总个数)。
需注意,为取最小移动次数,在实际移动时,当圆盘总数为偶数时,我们将第一个圆盘,即最小圆盘先移到B,当圆盘总数为奇数时,则先移到C。

二、编程中的汉罗塔问题

现在我们想要编写一个程序,输入n值,代表起始石柱上圆盘总数,然后让程序打印出移动步骤,来帮助我们完成搬运工作。

1.代码概览

#include<stdio.h>
Move(char pos1, char pos3)//打印移动步骤
{
	printf("%c->%c ", pos1, pos3);
}
Hanio(int n, char pos1, char pos2, char pos3)//pos1起始石柱,pos2中转石柱,pos3目的石柱
{
	if (n == 1)
	{
		Move(pos1, pos3);
	}
	else
	{
		Hanio(n - 1, pos1, pos3, pos2);//交换pos2,pos3
		Move(pos1, pos3);
		Hanio(n - 1, pos2, pos1, pos3);//交换pos1,pos2
	}
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	Hanio(n, 'A', 'B', 'C');
	return 0;
}

2.详解代码

我们来看看这段代码是如何实现的,先来看一张动图(以4个圆盘为例)
在这里插入图片描述
上图可以分为三个阶段

  1. pos3,将pos1最上面3个圆盘转移到pos2
  2. 交换pos1pos3,将最大的圆盘从pos1移至pos3
  3. pos1,将pos2上3个圆盘移至pos3上。

其实到此,我们已经说出了这段代码的精髓了。
上面我们提到:
1个圆盘是A->C
2个圆盘是A->B | A->C | B->C
3个圆盘是A->C A->B C->B | A->C | B->A B->C A->C
4个圆盘是A->B A->C B->C A->B C->A C->B A->B | A->C | B->C B->A C->A B->C A->B A->C B->C

易知,除了1个圆盘外,我们都可以用|划分出这个阶段。

1   Hanio(int n, char pos1, char pos2, char pos3)
2   {
3 	   if (n == 1)
4 	   {
5 		   Move(pos1, pos3);
6	   }
7	   else
8	   {
9		   Hanio(n - 1, pos1, pos3, pos2);
10		   Move(pos1, pos3);
11		   Hanio(n - 1, pos2, pos1, pos3);
12	   }
13  }

所以我们构造分支,如果n=1,则直接将圆盘从A搬到C,如果n>1,则else,第9行为第一阶段,第10行为第二阶段,第11行为第三阶段。
以n=3为例,运行逻辑如下:
在这里插入图片描述
所谓大事化小事,这是递归的意义所在,可以化繁为简。而图片中的’小事‘就是前文的三个阶段,即第一层递归的三个支线,其中的两个Hanio支线又可以细分、往复下去。可以发现一开始,从外到内,Hanio函数一直都是在传递形参,即‘’ ,直到n=1时,才进入‘’,这时这种循环往复从内到外继续进行。再深思,这种循环往复归根其实是pos1pos2pos3的循环往复。
建议大家对着运行逻辑图,拿纸笔将每一次交换都按顺序写下来,用心领悟,试着去分析一下,个例搞透了,整体思想也就容易理解了,最终递归,我们也就拿捏了。
其实简单地讲,递归无非就是一个从外‘递’至内,从内‘归’回外的过程,我们需要的只是明确递的是什么,归的是什么,这样就很容易理解汉罗塔问题了。


到此本篇就结束了,有什么不懂的可以在评论区一起交流探讨,学习与成长的道路上有个同伴总是不错的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

David猪大卫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值