首页 > 其他分享 >计算机初级选手的成长历程——汉诺塔问题详解

计算机初级选手的成长历程——汉诺塔问题详解

时间:2023-09-26 11:32:47浏览次数:39  
标签:函数 圆盘 move 递进 选手 详解 汉诺塔 HNT 移动

大家好,很高兴又和各位见面啦!在上一篇我们通过3道习题复习了一下函数的相关知识点,今天我们将讨论一个非常经典的问题——汉诺塔问题。

编写函数来解决汉诺塔问题:

(1)什么是汉诺塔?

简单的理解就是有三根柱子,其中一根柱子上有n个由上到下逐渐增大的圆盘,我们需要在保证圆盘始终是大圆盘在下,小圆盘在上的情况下每次移动一个圆盘,直到完成所有圆盘的移动。如图所示:

计算机初级选手的成长历程——汉诺塔问题详解_汉诺塔

我们需要在保证圆盘按照下面大上面小的顺序叠放的情况下将圆盘转移到其它柱子上。

(2)解题思路

移动流程

假设在A柱上有n个圆盘,我需要将圆盘从A柱转移到B柱,那我就需要按以下步骤完成转移:

将n-1个圆盘先转移到C柱,并按顺序叠放;

将第n个圆盘移动到B柱;

将n-2个圆盘再转移到A柱,并按顺序叠放;

将第n-1个圆盘移动到B柱;

不断重复前面四个步骤,每次需要转移的圆盘数量减1;

简化问题

为了将这个问题简单化,我们始终将圆盘看成1/2/3三个部分,然后进行移动;

第一步将1移动到B柱;

第二步将2移动到C柱;

第三步将1移动到C柱;

第四步将3移动到B柱;

第五步将1移动到A柱;

第六步将2移动到B柱;

第七步将1移动到B柱;

不断重复上述步骤,直到所有圆盘完成叠放。

功能实现

功能一——移动圆盘

计算机初级选手的成长历程——汉诺塔问题详解_汉诺塔_02

为了向大家展示移动过程,我们可以通过打印函数来表示圆盘的移动;

功能二——重复移动

需要实现重复移动的功能,首先我们就需要找出移动的共同点,这里我们先将圆盘看成两部分第n个圆盘和n-1个圆盘:

第一步,将n-1个圆盘从A柱移动到C柱;

第二步,将第n个圆盘从A柱移动到B柱;

第三步,将n-1个圆盘从C柱移动到B柱;

因此我们可以通过递归来重复上述操作:

//功能一——移动圆盘
void move(char A, char B, int n)
{
	//通过打印来展示圆盘的移动过程
	printf("第%d个圆盘从%c移动到%c\n", n , A, B);
}
//功能二——重复移动圆盘
void HNT(char A, char B, char C, int n)
{
	if (1 == n)//当圆盘只有1个时
	{
		//圆盘将从A柱移动到B柱
		move(A, B, n);
	}
	else//当圆盘不止一个时
	{//通过递归来实现圆盘移动的重复操作
		//n-1个圆盘将从A柱移动到C柱
		HNT(A, C, B, n - 1);
		//第n个圆盘将从A柱移动到B柱
		move(A,B, n );
		//第n-1个圆盘将从C柱移动到B柱
		HNT(C, B, A, n - 1);
	}
}

计算机初级选手的成长历程——汉诺塔问题详解_数学归纳法_03

如图所示,第一步我们需要借助B柱将n-1个圆盘全部从A柱移动到C柱,我们需要将参数A、C、n-1传给函数move以此将过程打印出来,即move(A,C,n-1),在代码中我们通过递归HNT函数来完成传参,即HNT(A,C,B,n-1)

计算机初级选手的成长历程——汉诺塔问题详解_汉诺塔_04

第二步,此时圆盘只有1个也就是此时n=1,我们将圆盘从A柱直接移动到B柱,此时我们需要将A、B、n传给函数move将过程打印出来,即move(A,B,n)

计算机初级选手的成长历程——汉诺塔问题详解_数学归纳法_05

第三步,我们需要将n-1个圆盘借助A柱从C柱移动到B柱,此时我们需要将C、B、n-1传给函数move以此将移动过程打印出来,即move(C,B,n-1),在代码中我们通过递归完成传参,即HNT(C,B,A,n-1);

代码解析

这里假设我们输入值为3,在进入HNT函数后,代码的运行流程如下所示:

  1. 此时HNT函数的形参为A='A',B='B',C='C',n=3;
  2. 判断3 != 1,执行第一个递进HNT函数的第一层递进HNT函数,此时的HNT函数的形参为A=A='A',B=C='C',C=B='B',n-1=2;
  3. 判断2 != 1,执行第一层递进HNT函数的第二层递进HNT函数,此时的HNT函数的形参为A=A=A='A',B=C=B='B',C=B=C='C',n-2=1;
  4. 判断1 == 1,执行嵌套函数move进行打印,此时的move函数形参为A=A='A',B=B='B',n-2=1;
  5. 打印内容为第1个圆盘从A移动到B,此时第二层递进HNT函数已经执行完,开始进行回归
  6. 回归第一层递进HNT函数,顺序执行第一层递进HNT函数的嵌套函数move进行打印,此时的move函数形参为A=A='A',B=B='C',n-1=2;
  7. 打印内容为第2个圆盘从A移动到C
  8. 回到第一层递进HNT函数,顺序执行第一层递进HNT函数的第二个递进HNT函数,此时的HNT函数的形参为:A=C=B='B',B=B=C='C',C=A=A='A',n-2=1;
  9. 判断1 == 1,执行嵌套函数move进行打印,此时的move函数的形参为A=A='B',B=B='C',n-2=1;
  10. 打印内容为第1个圆盘从B移动到C
  11. 回到第一层递进HNT函数,此时第一层递进HNT函数已经执行完,开始进行回归;

计算机初级选手的成长历程——汉诺塔问题详解_汉诺塔_06

  1. 回归到HNT函数,顺序执行HNT函数后续嵌套函数move,此时的move函数形参为A=A='A',B=B='B',n=3;
  2. 打印内容为第3个圆盘从A移动到B;
  3. 回到HNT函数,顺序执行HNT函数的第二个递进HNT函数的第一层递进,此时的HNT函数的形参为A=C='C',B=B='B',C=A='A',n-1=2;
  4. 判断2 != 1,执行第二层递进HNT函数,此时的HNT函数的形参为A=A=C='C',B=C=A='A',C=B=B='B',n-2=1;
  5. 判断1 == 1,执行嵌套函数move进行打印,此时的move函数的形参为A=A='C',B=B='A',n-2=1;
  6. 打印内容为第1个圆盘从C移动到A,此时第二层递进HNT函数已经执行完,开始进行回归
  7. 回归第一层递进HNT函数,顺序执行第一层递进HNT函数的嵌套函数move进行打印,此时的move函数形参为A=A='C',B=B='B',n-1=2;
  8. 打印内容为第2个圆盘从C移动到B
  9. 回到第一层递进HNT函数,顺序执行第一层递进HNT函数的第二个递进HNT函数,此时的HNT函数的形参为:A=C=A='A',B=B=B='B',C=A=C='C',n-2=1;
  10. 判断1 == 1,执行嵌套函数move进行打印,此时的move函数的形参为A=A='A',B=B='B',n-2=1;
  11. 打印内容为第1个圆盘从A移动到B此时第一层递进HNT函数已经执行完,开始进行回归

计算机初级选手的成长历程——汉诺塔问题详解_数学归纳法_07

  1. 回归到HNT函数,此时HNT函数全部执行完成,回到主函数,结束程序运行。

计算机初级选手的成长历程——汉诺塔问题详解_汉诺塔_08

代码理解的重难点在于参数的变化,大家可以参照流程图解以及文字解释来进一步理解汉诺塔函数通过递进的实现圆盘的重复移动。

功能三——计算次数

计算汉诺塔移动的次数的方式有很多,比如可以在move函数中加入计数变量,也可以通过公式来进行计算,这里我介绍一下通过公式进行计算移动次数。

汉诺塔移动次数的公式我们可以通过数学归纳法来求解;

圆盘数量(n)

移动次数f(n)

递推公式

1

1

1

2

3

2*f(1)+1

3

7

2*f(2)+1

4

15

2*f(3)+1

5

31

2*f(4)+1

……

n

2^n-1

2*f(n-1)+1

通过数学归纳法不难证明,因为第1个圆盘的移动次数为2^1-1,假设第n个圆盘的移动次数为2^n-1成立,那我只需要证明第n+1个圆盘的移动次数为2^(n+1)-1成立即可,;

根据递推公式可得,第n+1个圆盘的移动次数为2*f(n)+1=2*(2^n-1)+1=2^(n+1)-1,证明完毕。

由此我们可以尝试编写代码来求解圆盘的移动次数:

//功能三——计算次数
int num(int x)
{
	int n = pow(2, x) - 1;
	return n;
}

(3)汉诺塔问题的实现

通过前面的解题分析,我们已经将汉诺塔所需的三个功能的代码全部编写完毕,下面只需要将这三个功能整合起来,就可以了:

//功能一——移动圆盘
void move(char A, char B, int n)
{
	//通过打印来展示圆盘的移动过程
	printf("第%d个圆盘从%c移动到%c\n", n , A, B);
}

//功能二——重复移动圆盘
void HNT(char A, char B, char C, int n)
{
	if (1 == n)//当圆盘只有1个时
	{
		//圆盘将从A柱移动到B柱
		move(A, B, n);
	}
	else//当圆盘不止一个时
	{//通过递归来实现圆盘移动的重复操作
		//n-1个圆盘将从A柱移动到C柱
		HNT(A, C, B, n - 1);
		//第n个圆盘将从A柱移动到B柱
		move(A, B, n);
		//第n-1个圆盘将从C柱移动到B柱
		HNT(C, B, A, n - 1);
	}
}
//功能三——计算次数
int num(int x)
{
	int n = pow(2, x) - 1;
	return n;
}
int main()
{
	//生成ABC三根柱子
	char left = 'A', mid = 'B', right = 'C';
	//生成n个圆盘
	int n = 0;
	//输入圆盘的数量
	scanf("%d", &n);
	//通过汉诺塔函数实现移动
	HNT(left, mid, right, n);
	//移动完毕后打印圆盘移动次数
	printf("圆盘移动了%d次\n", num(n));
	return 0;
}

计算机初级选手的成长历程——汉诺塔问题详解_数学归纳法_09

(4)涉及知识点

在汉诺塔问题的求解过程中我们涉及到了一下知识点:

  • 函数的组成
  • 函数的参数
  • 函数的传值调用
  • 函数的嵌套调用与链式访问
  • 函数的声明和定义
  • 函数递归

这个问题算是对函数知识点的综合考察,咱们只有将这些知识点真正做到融会贯通了才能从容的应对这类问题,所以咱们还要继续努力才行呀!!!


结语

到这里咱们本章的内容就全部结束了,希望这些内容能够帮助大家更好的理解并能独立编写汉诺塔问题。接下来随着学习的深入,我会继续给大家分享我在学习过程中的感受。如果各位喜欢博主的内容,还请给博主的文章点个赞支持一下,有需要的朋友也可以收藏起来反复观看哦!感谢各位的翻阅,咱们下一篇见。

标签:函数,圆盘,move,递进,选手,详解,汉诺塔,HNT,移动
From: https://blog.51cto.com/u_16231477/7605976

相关文章

  • Python之html2text:将HTML转换为Markdown文档示例详解
    From: https://mp.weixin.qq.com/s/Pa3NDXOseyg0mIn869mbhQ-----------------------------------------------------------------------------------------hello大家好我是Monday,本文将详细介绍如何使用Python库中的html2text模块来实现将HTML转换为Markdown的操作,并提供示例......
  • Chrome插件manifest.json文件详解
    {//扩展名称"name":"MyExtension",//版本。由1到4个整数构成。多个整数间用"."隔开"version":"1.0",//manifest文件版本号。Chrome18开始必须为2"manifest_version":2,//描述。132个字符以内"......
  • USART-通信详解
    目录一.通信基本概念1.根据数据传输方式划分2.根据数据传输方向划分3.根据数据同步方式划分二.USART流程分析1.USART协议2.USART框图分析3.寄存器分析三.USART驱动代码1.寄存器方式驱动2.固件库方式驱动一.通信基本概念1.根据数据传输方式划分串行通信:一般是8......
  • 拦截器详解
       ......
  • python操作windows桌面实现鼠标、键盘操作,python之pyautogui库文档详解
    文章目录一、概述1、概述2、安装二、屏幕操作1、获取屏幕分辨率2、某个坐标是否在屏幕上3、获取当前鼠标位置三、鼠标操作1、移动鼠标2、点击操作3、滚轮操作4、记录光标小程序5、鼠标拖拽6、缓动/渐变(Tween/Easing)函数99、保护措施(FAILSAFE)99、延迟操作(PAUSE)四、键盘操作1、......
  • 初阶指针详解
    (目录)1.内存和地址内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的所以为了有效的使用内存,就把内存划分成一个个小块,这每一个小块被称为内存单元,每个内存单元的大小是1个字节为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该......
  • Java容器类详解
    Java的容器在Java中,我们想要保存对象可以使用很多种手段。最简单的就是数组。但是数组具有固定的尺寸,而通常来说,程序总是在运行时根据条件来创建对象,我们无法预知将要创建对象的个数以及类型,所以Java推出了容器类来解决这一问题。Java容器的基本概念Java容器类库是用来保存对象的,他......
  • dxf格式详解与在线打开、查看
    dxf格式简介dxf是一种CAD文件格式,是AutoCAD使用的一种内部文件格式。它用于存储AutoCAD图形的几何形状、图层、样式、标注等元素。dxf文件格式是AutoCAD社区中使用最为广泛的文件格式之一,因为它是一种免费的文件格式,并且可以很好地支持AutoCAD的版本更新。dxf格式文件结......
  • stp格式详解与在线打开、查看
    stp格式简介stp(StandardfortheExchangeofProductmodeldata)文件是CAD绘图软件的3D图形文件的格式(扩展名),其中包含三维对象的数据;提供对产品模型数据交换的支持。stp文件是基于ASCII格式符合stp应用协议ISO10303-21标准的正文编码的交换结构的三维图像数据。stp格式数据组成s......
  • Shp格式详解与在线打开、查看
    Shp格式简介shp格式是一种矢量数据格式,用于存储地理信息系统(GIS)数据。shp文件由Esri公司开发,用于表示点、线和多边形等要素,并记录它们的坐标和属性信息。shp格式通常用于存储和共享各种类型的GIS数据,如地图、地形、人口数据等。Shp格式数据组成shp文件由一系列有序的文件组成,这些文......