汉诺塔问题——【C语言】

一、汉诺塔问题是什么

简单来讲:
就是有三根柱子,记为A,B,C,其中A上有n个盘子,我们需要借助B,把A上的所有盘子都移动到C上,并且有两条规则:

  1. 大盘子不能在小盘子的上面
  2. 一次只能移动一个盘子

二、如何解决(递归)

分析

  1. 自顶向下,逐渐求精:
      汉诺塔问题的解决方式是自顶向下逐渐求精。首先,我们需要将最上面的圆盘移动到第三个柱子上,然后将剩余的圆盘移动到第二个柱子上,最后将最上面的圆盘移动到第二个柱子上。因此,这个问题可以分解为三个子问题,即将 n-1 个圆盘从第一个柱子移动到第二个柱子,将第 n 个圆盘从第一个柱子移动到第三个柱子,再将 n-1 个圆盘从第二个柱子移动到第三个柱子。这三个子问题可以分别递归解决,最终得到整个问题的解。

  2. 函数调用、递归和分治:
      为了解决汉诺塔问题,我们需要使用函数调用、递归和分治。具体来说,我们可以编写一个函数 hanoi(n, a, b, c),其中 n 表示要移动的圆盘数,a、b 和 c 分别表示三个柱子。该函数首先检查 n 的值,如果 n == 1,则直接将圆盘从柱子 a 移动到柱子 c;否则,该函数会将问题分解为三个子问题,并递归调用 hanoi() 函数来解决这些子问题。

  3. 形参与实参:
      在函数调用过程中,我们使用形参来表示函数的输入参数,而实参则是在函数调用时提供的具体数值。在汉诺塔问题中,形参 n、a、b 和 c 分别表示要移动的圆盘数和三个柱子。在函数调用时,我们需要提供实际的圆盘数和三个柱子的具体名称,如 hanoi(3, ‘A’, ‘B’, ‘C’)。

  4. 有意义、规范的标识符:
      在编写程序时,使用有意义、规范的标识符可以使代码更易于理解和维护。在汉诺塔问题中,我们可以使用有意义的变量名和函数名,如 n、a、b、c 和 hanoi()。这些标识符可以更好地表达程序的含义,并提高代码的可读性。

  5. 时间复杂度:
      汉诺塔问题的时间复杂度为 O(2^n),其中 n 是圆盘的数量。这是因为在每次递归调用中,我们需要移动 2 个圆盘。此外,在解决汉诺塔问题的过程中,我们需要进行 n 次递归调用,每次递归调用需要进行 3 次移动操作。因此,总的移动次数为 3^(n - 1),这是一个指数级别的复杂度。在实际应用中,当圆盘数量较大时,解决汉诺塔问题的时间复杂度会变得非常高。

  6. 递归栈:
      递归函数的调用过程需要使用递归栈来保存每个函数调用的状态。在汉诺塔问题中,每个递归调用会创建一个新的函数调用帧,并将其压入递归栈中。当递归调用返回时,对应的函数调用帧会被弹出,恢复到上一层调用的状态。因此,在解决汉诺塔问题的过程中,递归栈的深度等于递归调用的层数,即 n。

  7. 空间复杂度:
      汉诺塔问题的空间复杂度为 O(n),其中 n 是圆盘的数量。这是因为在解决问题的过程中,我们需要使用一个递归栈来保存每个递归调用的状态。由于递归栈的深度等于递归调用的层数,因此空间复杂度为 O(n)。除了递归栈之外,我们还需要使用一些额外的变量来保存问题的状态,但这些变量的数量与圆盘的数量无关,因此不会影响空间复杂度。


如果是一个盘子的话,我们只需,直接将他移动到C:
A -> C
如果是两个盘子的话,我们需要先将小盘子移到B,再将大盘子移到C,最后将小盘子移到C:
A -> B A -> C B -> C
如果是三个盘子的话,同上:
A -> C A -> B C -> B A -> C B -> A B -> C A -> C
下面是动图演示:
请添加图片描述
在进行四个盘子的操作时我们会发现移动就不是那么简单了,次数程指数般的增长,他的移动次数是2的n次方减1;那么我们可以回过头来仔细观察三个盘子的移动,
递归思想下:就会发现:所有的操作都是先把A上面的两个盘子通过C移动到B上面,在把A上最后一个移动到C上,最后再把B上的两个盘子移到C上。
那么n个盘子的规律也是如此了!

三、代码实现

我们可以通过以下代码把盘子移动的过程:

#include <stdio.h>
void move(char pos1,char pos2)
{
	printf("%c -> %c  ", pos1, pos2);
}
/*
n:代表盘子的个数
pos1:起始位置
pos2:中转位置
pos3:目的位置
*/
void Hanoi(int n,char pos1,char pos2,char pos3)
{
	if (n == 1)
	{
		move(pos1, pos3);
	}
	else
	{
		Hanoi(n - 1, pos1, pos3, pos2);//把n-1个盘子移到B上
		move(pos1, pos3);//把A上最后一个盘子移到C上
		Hanoi(n - 1, pos2, pos1, pos3);//最后把B上n-1个盘子移到C上
	}
}
int main()
{
	Hanoi(1, 'A', 'B', 'C');
	printf("\n");
	Hanoi(2, 'A', 'B', 'C');
	printf("\n");
	Hanoi(3, 'A', 'B', 'C');
	printf("\n");
	return 0;
}

运行结果:
在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值