C语言实现汉诺塔问题(保姆式讲解)

2023-05-16

前言:

大家好,又是再一次分享文章,我十分感谢各位能够点开这篇花费我颇多时间才解决的汉诺塔问题,接下来我就要分享一下自己的所思所想,希望能给各位带来一些不一样的收获吧。

提醒:

汉诺塔问题的本质是函数递归,而函数递归已经是我们现阶段学习的C语言函数内容的后期知识,所以各位要想了解汉诺塔问题,请先学习好与函数有关的一些基本与重要的知识,还请各位多多理解。

说明:

我认为了解一个东西最重要是重复的实践,所以大家想要更好的了解汉诺塔问题,可在4399小游戏中或以其他方式去玩一玩,一定会加深你的认知的。


目录

1. 问题简述(以三层为例)

2. 背景

3. 数学思想

4. 执行过程的具体分析

(1) 过程简易分析(以三层为例)

(2) 思考

(3) 解答

(4) 递归说明

5. 整体代码及显示效果

6. 寄语


注意: 目录4.是整个汉诺塔问题最重要的部分,主要涉及了函数的递归问题,我会将每次的递归步骤在图纸上演示一遍(图有点丑,别嫌弃哈),以便大家更好的理解。我更希望如果各位真的想好好了解这个汉诺塔问题,就不要畏惧,其实并不难,认真看过程,我已经很详细地讲述我的理解了,希望能加深各位对汉诺塔问题的认识。


1. 问题简述(以三层为例)

(1)有三根柱子A,B,C。A柱上有n个盘子

(2)每次移动一个盘子,小的只能放在大的上面

(3)将所有盘子从A杆经过B杆全部移到C杆上d332a7d1b76a4712b551a988d7109efc.jpeg

2. 背景

法国数学家爱德华·卢卡斯曾编写过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。

大家听了这个背景故事有没有对汉诺塔产生更大的兴趣呢,毕竟它与世界末日息息相关嘛,但是我们真的等得到那一天吗?

3. 数学思想

其实汉诺塔问题只是一个简单的数学问题,由分析易知:

如果考虑把64片金片,由一根柱子上移到另一根柱子上,并且始终保持上小下大的顺序。这需要多少次移动呢?这里可以先进行枚举,找到对应的数学规律假设有n片,移动次数是f(n)。则有:

747f7b98f0994c7593a579b2be09880a.png

由上述分析可以得到两个函数关系:   (1) f(n)=2^n-1  (2) f(n)=2*f(n-1)+1

而由我们之前在C语言中学到的函数递归知识可知,可以将数学函数关系式利用在代码中,形成一个求移动步数的函数递归式。相关代码如下:

9592b13668ac454b9f5748598d57f119.png

这样就可以简单的知道n层汉诺塔问题需要移动的步数了。

所以可知当n=64时,假如每秒钟一次,一个平年365天有31536000秒,闰年366天有31622400秒,平均每年31557600秒,计算得:18446744073709551615秒,大约5900亿年,可能到时太阳系真的毁灭了,但是我能肯定的是我以及各位怕是看不到那天了。

补充:在后面的刷题过程中,我遇到了一种汉诺塔问题的进阶题,就是移动盘子的过程中只能够相邻柱间移动,这里仅仅补充一下这个问题的结论——移动次数f(n)=3^n-1,就不多多介绍了,有兴趣的可以自己去了解下。

                                      重点知识前来张晚霞图,给各位放松放松哈

4. 执行过程的具体分析(重要理解)

(1) 过程简易分析(以三层为例)

30c3817e790d4c89af0d7ae229a43131.jpeg

起始柱命名为‘A’,中转柱命名为‘B’,目的柱命名为‘C’,所以可以得到操作顺序为:

A-->C,A-->B,C-->B,A-->C,B-->A,B-->C,A-->C;共七步。

7801316a842643089629b0ed4e1c45c9.jpeg

由上述简单分析可以得到汉诺塔问题的三步过程:

           一: 将n-1个盘子从A杆经过C杆移到B杆

968035b63c074169afab75ffdf7bd8b0.jpg

           二: 将A杆上第n个盘子移到C杆上

 d19d46eb6502426090698b83370cc6a9.jpg

           三: 将B杆上的n-1上盘子经过A杆移到C杆上

2aced34e629c47fc9e6fef3e761bb7e1.jpg

    这样经过三步后,一个汉诺塔就完成了。

(2) 思考

由上述分析也可以知道这是一个相似且反复的过程,因此由我们以往的经验也可以得出整个过程满足函数递归。而既然是一个函数递归问题,那就有两个问题我们值得思考。

(1) 这个递归的中相似的部分是什么?即要找到函数递归的条件。

(2) 这个递归的出口是什么?即我们要如何做才能趋于这个递归的出口,找到这个递归的终止语句。

解决这两个问题,我们也就能很好的理解汉诺塔问题中的函数递归。

(3) 解答

通过我们对三层汉诺塔的分析,我们可以知道汉诺塔问题的本质,即将A杆中的n个盘子通过B杆全部移到C杆上,这样我们就可以简单的写下这个函数HNtower(n,A,B,C),并且我们可以找到其中的相似部分。

(4) 递归说明

(1)要将A杆上的n-1个盘子通过C杆移到B杆(第一步)

这里就可以与我们定义的汉诺塔函数联系起来,而得出递归的第一层HNtower(n-1,A,C,B)

(2)要将B杆上的n-1个盘子通过A杆移到C杆上(第三步)

 这样可以得到递归的第二层HNtower(n-1,B,A,C)

但是,由三层汉诺塔也可以知道在函数递归过程中只有这两步也不够,我们除了找到这两个相似点外,还有一个十分重要的条件,那就是我们还需要在两步递归中定义调用一个移动函数Move(A,C);而由这个函数的两个参数我们也可以知道它的作用:将A杆的盘子移到C杆上(即在执行完第一步后,我们要将A杆上剩余的最大盘移到C杆上),即4c1f8404eb4d4ecbbeefbc4d29856667.png

递归出口:

找到这两层递归后,我们已经解决了汉诺塔问题的一半了,但是还有一个很重要的,也就是

这个递归的出口。而要找到这个出口,其实也不难,我们可以想一想,一个程序的出口是什么呢?无非就是这个程序的最后一步,而汉诺塔的最后一步可以简化为一层汉诺塔问题(即将1个盘子从A杆直接移到C杆上),这样我们也就找到了这个递归的出口,也就是(n<=1)。

但是我们又要怎样趋于这个出口呢?其实这个问题我们早就解决了,递归中的第一个参数(n-1)在递归多次进行之下不就会趋于这个出口,所以我们在思考递归函数的参数时十分重要,这就要我们多多练习与函数递归有关的习题来培养一种思维能力(小编的思维能力也很差,我们一起加油)。

由上述分析,我们就可以得到这个汉诺塔函数的相关代码04d9d12dc6b543318c58170b5e94cfd6.png

 79dcf852771741aaa608957a0407042c.png

 图示分析递归实现的过程:

注:图是在纸上画的,我已经尽量保证清晰度以及完整的过程了,希望大家能认真分析一下,如果觉得不方便看,我建议可以抄写一份在自己的纸上慢慢分析。(图上的小记号要注意哈)

提醒一下哈,下三张图表示了三层汉诺塔的六次传参以及五次递归,其中的大写数字(一,二,三等等)是各个传参过程具体分析,而不同张纸上相同数字表示的是同一个函数(主要是我觉得要把相关性强的部分放在一起,导致了一些重复函数在不同的纸上,大家要分清楚)。

5e2f35e5fb0640f9ab5dd3a824f2b455.jpg

41ee141523894723b07d6db2f5eda8e9.jpg

dad392683098419fb7a8e96e98b07915.jpg

为了各位能更好的理解,我会将图示简要分析一下。

细品:

我在图中汉诺塔函数的各个参数上标明了一些小写字母(x,y,z)作为识别标志。将起始过程的A柱标记为x,B柱标记为y,C柱标记为z,我们可以将传参过程中参数的变化转换成标记字母的变化以便观察。
汉诺塔问题的递归分析其实并不难,主要是我们要区分与函数参数以及函数在传参过程中对应参数分别表示什么。(即图中x,y,z在传参过程的变化)

在此我要说明一下:在函数内部调用参数时,是对应字符对应相关参数,而函数传递参数时,则是对应参数位置对应相关参数。

8db378bad4634f95ba46dfbf87a0cbc0.jpg

 再次强调图中x,y,z是我为了分析而规定的,实际并不存在,真正过程对应的还是柱子的标号(A,B,C),希望各位好好区分,好好理解一下。

5. 整体代码及显示效果

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void Move(char x, char y)
{
	printf("%c --> %c\n", x, y);
}
void HNtower(int a, char A, char B, char C)//汉诺塔函数实施主体,A为初始柱,B为经由柱,C为目的柱
{
	if (a == 1)
	{
		Move(A, C);
	}
	else
	{
		HNtower(a - 1, A, C, B);//第一个递归式
		Move(A, C);
		HNtower(a - 1, B, A, C);//第二个递归式
	}
}
int MoveNum(int a)
{
	if (a == 1)
		return 1;
	else
		return 2 * MoveNum(a - 1) + 1;//为了对应递归主题,用递归式表示
}
int main()
{
	int a = 0;
	printf("请输入你选择的层数:>");
	scanf("%d", &a);
	int Num = MoveNum(a);
	printf("%d层需要移动%d步\n", a, Num);
	printf("具体过程如下\n");
	HNtower(a, 'A', 'B', 'C');//进入递归函数
	return 0;
}

 整个汉诺塔问题就讲解到这里了,希望大家可以好好理解一下,也可以在评论区给我一些建议,谢谢各位光顾,万分感谢。

 6. 寄语

这篇文章小编还是花了一些时间的,希望大家可以好好思考一下,特别是分析清楚其中的递归过程(文章中三张图),希望我的分享可以给各位带来一些帮助吧。那这次的分享到此结束了,请大家好好期待一下小编的下一篇文章吧。

小小宣传:如果各位觉得这篇文章对你有些帮助或是有可学可取之处,还望可以分享给身边其他人,谢谢喽,各位,拜拜 ,下回再见!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言实现汉诺塔问题(保姆式讲解) 的相关文章

  • C#工控上位机开发-->1、C#快速编程入门

    学习目标 xff1a 一 控制台的输入输出二 C 中的变量使用三 字符串的拼接与格式化的三种方式四 数据类型转换的三种方式 学习内容 xff1a 1 控制台的输入输出 xff08 1 xff09 输入方法 xff1a Console Rea
  • C#工控上位机开发---2.面向对象编程

    学习目标 xff1a 1 对象与类的概念 2 类的组成 3 字段 属性 方法 4 属性扩展 学习内容 xff1a 1 1 对象与类的概念 xff1a 类就是以对象共有的属性 xff0c 方法来定义的一个整体 xff0c 也就是一类 xff0
  • ubuntu16.04配置JDK环境变量(JDK8u2)

    一 流程 1 官网下载JDK 2 解压缩 放到指定目录 3 配置环境变量 4 设置系统默认JDK 5 测试jdk 二 步骤 1 官网下载JDK xff08 下载jdk8为例 xff09 https www oracle com techne
  • STM32的一键下载CH340 DTR RTS与复位电路NRST的学习笔记

    这两天在学习stm32最小系统板的时候 对这一部分特别的不理解 于是就去找了很多东西去看 先说一键下载电路吧 先引用一张正点原子的原理图 xff1a 在芯片手册上查找ch340的手册 xff0c 上面对于 RTS与DTR的定义是这样的 xf
  • Linux学习笔记——逻辑卷及vdo的建立

    目录 前言 一 逻辑卷 1 如何建立lvm设备 xff1a xff08 1 xff09 lvm的拉伸 xff08 2 xff09 lvm缩减 xff08 3 xff09 lvm快照 xff08 4 xff09 lvm删除 二 vdo Vir
  • BGP路由器协议排错教程:BGP 对等体翻动问题

    完整版下载 2022年最新BGP路由协议排错教程指南 网络安全文档类资源 CSDN下载 BGP 对等体失效问题讨论的是当 BGP 邻居关系总是在 Idle xff08 空闲 xff09 状态和 Active xff08 活跃 xff09 状
  • VUE 事件总线

    VUE 事件总线 事件总线通俗理解为在平级的兄弟组件上的传参 1 将事件总线挂载到原型上 span class token keyword new span span class token class name Vue span span
  • 一看就懂的java虚拟机内存区域划分

    一 虚拟机 同样的java代码在不同平台生成的机器码肯定是不一样的 xff0c 因为不同的操作系统底层的硬件指令集是不同的 同一个java代码在windows上生成的机器码可能是0101 xff0c 在linux上生成的可能是1100 xf
  • 硬核,20道经典Java基础面试题

    最近整理了20道Java基础面试题 xff0c 大家一起加油哈 1 ArrayList和LinkedList有什么区别 xff1f 可以从它们的底层数据结构 效率 开销进行阐述哈 ArrayList是数组的数据结构 xff0c Linked
  • 面向无人机的视觉目标跟踪算法:综述与展望

    摘要 近年来 无人机因其小巧灵活 智能自主等特点被广泛应用于民用和军事等领域中 特别是搜索侦察过程中首要的目标跟踪任务 无人机视觉目标跟踪场景的复杂性和运动目标的多变性 使得目标特征提取及模型建立困难 对目标跟踪性能带来巨大的挑战 本文首先
  • 网络空间对抗防御中的智能监测技术研究

    摘 nbsp nbsp 要 nbsp 网络空间数据流观测与威胁行为分析是国家网络空间安全防御中的重要方向 为 nbsp nbsp nbsp 应对国家网络空间大规模数据流观测和不断涌现的网络威胁对抗防御重大需求 针对传统 nbsp nbsp
  • Promethues (普罗米修斯)详细介绍

    目录 引言 一 Prometheus 概述 1 什么是Prometheus 2 Zabbix和Prometheus区别 3 Prometheus的特点 二 运维监控平台设计思路 三 Prometheus监控体系 1 系统层监控 xff08
  • 使用vue对表格数据进行查询

    大家好 xff0c 今天小明给大家带来一个带有查询框 的表格 xff0c 下面给大家瞅瞅效果图片 xff1a 带查询框的表格 xff0c 查询前的效果图 带查询框的表格 xff0c 查询后的效果图 从效果图上可以看出 xff0c 在查询框内
  • Linux操作系统面试总结

    1 系统启动流程 uboot gt kernel gt 根文件系统 uboot第一阶段属于汇编阶段 xff1a 定义入口 xff08 start S xff09 xff1a uboot中因为有汇编阶段参与 xff0c 因此不能直接找main
  • 详谈静态库和动态库的区别

    一 什么是库 xff1a 库是写好的 xff0c 现有的 xff0c 成熟的 xff0c 可以复用的代码 现实中每个程序都要依赖很多基础的底层库 xff0c 不可能每个人的代码都从零开始 xff0c 因此库的存在意义非同寻常 本质上来说 x
  • HDFS读取流程

    在HDFS的读写流程中 xff0c 主要是分为HDFS的读流程和写流程 其中先由HDFS写数据 xff0c 之后HDFS才可以读流程 HDFS写流程 Client向NameNode发送消息 xff0c 通过RPC与NameNode建立通信
  • 删除图片名与xml(json)文件名称不对应的

    1 文件夹下无目录文件夹 xff08 纯文件 xff09 import os def scanfile path 获取图片路径 xff08 列表格式 xff09 filelist 61 os listdir path for filepat
  • FreeRTOS内存不够

    STM32F103 xff0c RAM大小为20K xff0c 看起来还是很多的 xff0c 但一运行FreeRTOSG有点功能的程序马上就内存不够了 xff1b unable to allocate space for sections

随机推荐

  • FreeRTOS 任务之间运行时序

    操作系统 xff0c 我们肯定会创建许多任务 xff0c 而且任务的优先级不一样 xff0c 但我们一般情况是采用抢占模式 xff0c 也就是一直运行当前最高优先级任务 xff0c 那么其他低优先级任务就无法运行 xff0c 这时候需要通过
  • c语言-查找指定字符

    题目源自pta xff0c 侵删 本题要求编写程序 xff0c 从给定字符串中查找某指定的字符 输入格式 xff1a 输入的第一行是一个待查找的字符 第二行是一个以回车结束的非空字符串 xff08 不超过80个字符 xff09 输出格式 x
  • linux查看日志文件内容命令sed、cat、tac、more、less、head、tail、echo 1、按时间查询

    查询日志 xff1a linux查看日志文件内容命令sed cat tac more less head tail echo 1 按时间查询 sed n 39 2017 09 20 14 00 2017 09 20 15 00 p 39 c
  • 计算机保研面试经验分享—重庆大学

  • uCOS学习笔记——实时操作系统概述

    一 概述 RTOS real time operation system 既实时操作系统 通俗来说 xff0c 实时操作系统正如一个大管家一般 xff0c 可以根据任务的要求 xff0c 进行资源管理 xff0c 消息管理 xff0c 任务
  • windows HLK server部署操作步骤

    Windows Hardware Lab Kit HLK 微软官方提供的测试工具组 xff0c 也是微软的一种认证工具 xff0c 只有经过HLK测试过的windows系统 xff0c 官方才认可 The Windows Hardware
  • uCOS学习笔记----任务管理

    一 任务管理 一 任务的概念 从前文得知 xff0c uCOS可以将裸机中庞大的while 1 循环拆解为执行不同功能的小程序 xff0c 并依据一定的规则调度任务的运行 这些小程序就被称为任务 一般而言 xff0c 任务由三个部分构成 x
  • 想说说关于在刷题网站(牛客 、C语言网、力扣)上测试样例过了但是OJ判错这档子事

    目录 1 话题引入 2 在刷题过程中一些自己想说的 3 刷题时的一些小建议 4 个人感悟 1 话题引入 首先介绍一下我自己 xff0c 本人是一名专科大一的学生 xff1b 非计算机本专业 xff1b 因为想拓宽自己的知识面和技术 xff1
  • Java实现爬虫

    目录 xff1a 1 爬虫原理 2 本地文件数据提取及分析 3 单网页数据的读取 4 运用正则表达式完成超连接的连接匹配和提取 5 广度优先遍历 xff0c 多网页的数据爬取 6 多线程的网页爬取 7 总结 爬虫实现原理 网络爬虫基本技术处
  • Python+ADB脚本

    目录 准备工具 问题解决 xff1a 如何安装adb和python xff1f 编写程序 实现 注意 xff1a 准备工具 进入正题 xff0c 首先要准备的工具如下 1 一台正常的电脑且安装adb和python环境 2 一部安卓手机 4
  • (++i)+(++i)+(++i)计算的探讨

    今天在进行着代码选择题练习的时候 xff0c 我忽然看到了这一题 我左思右想 xff0c 发现答案应当是 xff08 2 xff09 43 xff08 3 xff09 43 xff08 4 xff09 61 9 xff0c 可我仍然保有着疑
  • 超详细讲解长度受限制的字符串函数(保姆级教程!!!)

    超详细讲解长度受限制的字符串函数 xff08 保姆级教程 xff01 xff01 xff01 xff09 长度受限制的字符串函数strncpy函数strncpy函数的使用strncpy函数的模拟实现 strncat函数strncat函数的使
  • 超详细讲解字符串查找函数(保姆级教程!!!)

    超详细讲解字符串查找函数 xff08 保姆级教程 xff01 xff01 xff01 xff09 字符串查找函数strstr函数strstr函数的使用strstr函数的模拟实现 strtok函数strtok函数的使用strtok函数的模拟实
  • 超详细讲解线性表和顺序表!!

    超详细讲解线性表和顺序表 xff01 xff01 线性表顺序表顺序表的概念及结构静态顺序表动态顺序表 顺序表接口实现1 创建2 初始化3 扩容4 尾插5 打印6 销毁7 尾删8 头插9 头删10 插入任意位置11 删除任意位置12 查找13
  • Leetcode—移除元素、删除有序数组中的重复项、合并两个有序数组

    移除元素 此题简单 xff0c 用双指针方法即可 xff0c 如果右指针指向的元素不等于val xff0c 它一定是输出数组的一个元素 xff0c 我们就将右指针指向的元素复制到左指针位置 xff0c 然后将左右指针同时右移 xff1b 如
  • 超详细讲解C语言文件操作!!

    超详细讲解C语言文件操作 xff01 xff01 什么是文件文件名 文件的打开和关闭文件指针文件的打开和关闭 文件的顺序读写文件的随机读写fseekftellrewind 文本文件和二进制文件文件读取结束的判定文件缓冲区 什么是文件 磁盘上
  • windows HLK server部署操作步骤

    Windows Hardware Lab Kit HLK 是微软官方提供的一个测试工具组 xff0c 也是windows系统认证工具 The Windows Hardware Lab Kit Windows HLK is a test fr
  • 超详细讲解Java的数据类型与变量

    超详细讲解Java的数据类型与变量 字面常量数据类型变量整型变量长整型变量短整型变量字节型变量 浮点型变量双精度浮点型单精度浮点型 字符型变量布尔型变量 转换自动类型转换 隐式 强制类型转换 显式 类型提升 字面常量 在System Out
  • java.lang.instrument ASSERTION FAILED ***: “error

    java lang instrument ASSERTION FAILED error 61 61 JVMTI ERROR NONE at Reentrancy c line 161 问题记录 应该是jdk版本更新的问题 第一次运行代码时出
  • C语言实现汉诺塔问题(保姆式讲解)

    前言 大家好 xff0c 又是再一次分享文章 xff0c 我十分感谢各位能够点开这篇花费我颇多时间才解决的汉诺塔问题 xff0c 接下来我就要分享一下自己的所思所想 xff0c 希望能给各位带来一些不一样的收获吧 提醒 汉诺塔问题的本质是函