汉诺塔问题C语言递归(详细)

什么是汉诺塔问题

汉诺塔问题是一个经典的问题。汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。问应该如何操作?(每次只能移动1个盘子,大盘子只能放在小盘子下面)
请添加图片描述

这里还有一个预言: 当所有的金片都从梵天穿好的那根针上移到另外一概针上时,世界就将在一声霹雳中消灭,梵塔、庙宇和众生都将同归于尽,也就是世界毁灭。

想要把64片金片从一根针上全部需要多长时间呢?也就是说世界毁灭会多长时间呢?让我们往下看

汉诺塔问题的实现

简单汉诺塔的推理

一个盘子

  • 当只有一个盘子的时候,很直接的看出,只需移动一次

在这里插入图片描述

两个盘子

  • 有两个盘子时,就需要借助第三个柱子才能实现

第一步:在这里插入图片描述
第二步:在这里插入图片描述
第三步:

最终:在这里插入图片描述

  • 如图,最终需要三步

三个盘子

第一步和第二步:
在这里插入图片描述
第三步:在这里插入图片描述
第四步:
在这里插入图片描述
第五步:
在这里插入图片描述
第六步,第七步:
在这里插入图片描述

  • 所以如图,三个盘子需要移动7次

汉诺塔问题的实现

偏数学方式的实现

以三个盘子为例:
先把三个盘子想象成一个盘加两个盘子(并且把这两个盘子看成整体)
在这里插入图片描述
先把这个整体移动到B柱上:
在这里插入图片描述
在把A柱上的那一个盘子移动到C主上
在这里插入图片描述
最后,再将两个盘子整体移动到C上在这里插入图片描述

  • 所以从始至终,一个盘和那两个盘子的整体只移动了三次,其中独自的那个盘子从A到C移动两次,两个盘子的整体移动了两次
  • 可以看出,两个盘子每次整体的移动都是一个含有两个盘子的汉诺塔问题

所以,假设n是圆盘的数量,T(n)是移动n个圆盘的移动次数。
当n=1时,T(1)=1
当n=2时,T(2)=2T(1)+1
当n=3时,T(3)=2T(2)+1
……

就可以得出:在这里插入图片描述
也很容易得到公式: f(n) = 2^n-1

代码的实现:

int Hanoi(int n)
{
	if (n == 1)
	{
		return 1;
	}
	else
	{
		return 2*Hanoi(n - 1) + 1;
	}
}
int main()
{
	int n = 0;
	printf("输入A塔中盘子个数");
	scanf("%d", &n);
	printf("总共挪动的次数为:%d\n", Hanoi(n));
	return 0;
}

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

偏过程方式的实现

从含有两个盘子的汉诺塔中可以看出来:
1号盘是借助于B柱,才最终到达A柱2号盘直接从A柱到C柱
在这里插入图片描述
再分析一下含有三个盘子的汉诺塔:
1号整体是借助柱到达B柱,
2号盘直接从A柱到C柱,
最终把整体借助A移动到C上
其中对于1号整体的移动就是含有两个盘的汉诺塔问题在这里插入图片描述>所以,以此类推,n个盘的汉诺塔,它的从上到下前n-1个盘是通过C柱到达B柱,最下面的一个盘是由A直接到C,最后再把整体借助A柱移动到C柱

代码实现:

void move(char x,char y)
{
	printf("从 %c 移动到 %c\n", x, y);
}


void Hanoi2(int n, char A, char B, char C)
{
	if (n == 1)       //只有一个盘子
	{
		ShowMove(A, C);  //直接移动即可
	}
	else
	{
		Hanoi2(n - 1, A, C, B);    //将上边n-1个盘子从a上借助c到达b
		ShowMove(A, C);    
		Hanoi2(n - 1, B,A,C);      //将上边n-1个盘子从b上借助a到达c
	}
}
int main()
{
	int n = 0;
	printf("输入A塔中盘子个数");
	scanf("%d", &n);
	Hanoi2(n, 'A', 'B', 'C');
	return 0;
}

代码解读:
move(char,char)函数是为了从A柱上把最下面的盘子移动到C柱
void Hanoi2(int n, char a, char b, char c)中,形参n是盘子个数,a,b,c表示盘子在a上,借助b,最终到达c

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

  • 全部代码:
#include <stdio.h>
int Hanoi(int n)
{
	if (n == 1)
	{
		return 1;
	}
	else
	{
		return 2*Hanoi(n - 1) + 1;
	}
}

void ShowMove(char x,char y)
{
	printf("从 %c 移动到 %c\n", x, y);
}


void Hanoi2(int n, char a, char b, char c)
{
	if (n == 1)
	{
		ShowMove(a, c);
	}
	else
	{
		Hanoi2(n - 1, a, c, b);
		ShowMove(a, c);
		Hanoi2(n - 1, b,a,c);
	}
}
int main()
{
	int n = 0;
	printf("输入A塔中盘子个数");
	scanf("%d", &n);
	printf("总共挪动的次数为:%d\n", Hanoi(n));
	Hanoi2(n, 'A', 'B', 'C');
	return 0;
}

预言解读

根据前面得到的公式,当n为64时,需要移动2^64-1 = 18446744073709551615次
假如每秒钟一次
18446744073709551615÷31556952=584554049253.855年
移完这些金片需要5845亿年以上
所以到时候世界是否毁灭就不管你我的事啦! ~

  • 13
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

疯癫了的狗

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

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

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

打赏作者

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

抵扣说明:

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

余额充值