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

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

什么是汉诺塔问题


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

820cdb19320d4975ba5a1f23b1b8ae12.gif


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


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


汉诺塔问题的实现


简单汉诺塔的推理

一个盘子

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


749dffb697c44122985c52aa81a2f710.png

两个盘子

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

第一步:497c3ce7c4444a03a7483a90456318b4.png

第二步:

第三步:0b0fda9d4e4c4bea84aca97d5ff62bb5.png


最终:ebba793003fc4774a9e89932eeb0ece2.png


如图,最终需要三步

三个盘子

第一步和第二步:

a15242aa0ba74f21b9e5e3996ae86cbb.png

第三步:0bde74505f9f4e36bf252ba4047ce701.png

第四步:

6a4efe5c2d1a4b22a28c2cd685ec64ec.png

第五步:

26b01cfedcf64ecb8e2e674309f0fb5e.png

第六步,第七步:

6b447ff997744445b239f914f16d0d8f.png


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

汉诺塔问题的实现

偏数学方式的实现

以三个盘子为例:

先把三个盘子想象成一个盘加两个盘子(并且把这两个盘子看成整体)

45ca69e19a5047d8818b277c5f66a5dc.png

先把这个整体移动到B柱上:

c30cf11f9e6f4400a48996b510a6e4cc.png

在把A柱上的那一个盘子移动到C主上

07037e588df048bb9b44f20dc564558d.png

最后,再将两个盘子整体移动到C上


所以从始至终,一个盘和那两个盘子的整体只移动了三次,其4b102757d2ef433c80ec84572148b49e.png中独自的那个盘子从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

……


就可以得出:20ce25553a06491c8f960e36d78d6996.png

也很容易得到公式: 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;
}




结果:0838e9c5e0644d7ab0453d134258c7cf.png


偏过程方式的实现

从含有两个盘子的汉诺塔中可以看出来:

1号盘是借助于B柱,才最终到达A柱2号盘直接从A柱到C柱

7747237c3ea543ffb2ea93e408e01dea.png

再分析一下含有三个盘子的汉诺塔:

1号整体是借助柱到达B柱,

2号盘直接从A柱到C柱,

最终把整体借助A移动到C上419ccb2f03d84dd8b1eacce49ac64927.png

其中对于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


结果:

6726b6f3ec2e4a85b545795248bef5d4.png


全部代码:

#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亿年以上

所以到时候世界是否毁灭就不管你我的事啦! ~


目录
相关文章
|
4月前
|
机器学习/深度学习 C语言
九/十:《初学C语言》— 扫雷游戏实现和函数递归基础
【8月更文挑战第5天】本篇文章用C语言采用多文件编写实现了一个基础的扫雷游戏(附源码),并讲解了关于函数递归的基础概念及其相对应的习题练习(附源码)
43 1
九/十:《初学C语言》— 扫雷游戏实现和函数递归基础
|
2月前
|
机器学习/深度学习 C语言
【c语言】一篇文章搞懂函数递归
本文详细介绍了函数递归的概念、思想及其限制条件,并通过求阶乘、打印整数每一位和求斐波那契数等实例,展示了递归的应用。递归的核心在于将大问题分解为小问题,但需注意递归可能导致效率低下和栈溢出的问题。文章最后总结了递归的优缺点,提醒读者在实际编程中合理使用递归。
62 7
|
2月前
|
C语言
c语言回顾-函数递归(上)
c语言回顾-函数递归(上)
34 2
|
2月前
|
C语言
c语言回顾-函数递归(下)
c语言回顾-函数递归(下)
40 0
|
4月前
|
机器学习/深度学习 C语言
【C语言篇】递归详细介绍(基础概念习题及汉诺塔等进阶问题)
要保持最小的步数,每一次汉诺塔问题(无论是最初还是递归过程中的),如果此时初始柱盘子数为偶数,我们第一步是把最上面的盘子移动到中转柱,如果为奇数,我们第一步则是将其移动到目标柱。
84 0
【C语言篇】递归详细介绍(基础概念习题及汉诺塔等进阶问题)
|
4月前
|
C语言
C语言中的递归
C语言中的递归
|
5月前
|
存储 编译器 C语言
|
4月前
|
算法 编译器 C语言
【C语言】递归
【C语言】递归
22 0
|
6月前
|
机器学习/深度学习 算法 C语言
详细介绍递归算法在 C 语言中的应用,包括递归的基本概念、特点、实现方法以及实际应用案例
【6月更文挑战第15天】递归算法在C语言中是强大力量的体现,通过函数调用自身解决复杂问题。递归涉及基本概念如自调用、终止条件及栈空间管理。在C中实现递归需定义递归函数,分解问题并设定停止条件。阶乘和斐波那契数列是经典应用示例,展示了递归的优雅与效率。然而,递归可能导致栈溢出,需注意优化。学习递归深化了对“分而治之”策略的理解。**
121 7
|
6月前
|
C语言
C语言--函数递归与迭代
C语言--函数递归与迭代