汉诺塔递归算法/搬金盘的婆罗门 - Python实现

article/2025/9/9 8:02:18

汉诺塔递归算法/搬金盘的婆罗门 - Python实现

本文引用自作者编写的下述图书; 本文允许以个人学习、教学等目的引用、讲授或转载,但需要注明原作者"海洋饼干叔
叔";本文不允许以纸质及电子出版为目的进行抄摘或改编。
1.《Python编程基础及应用》,陈波,刘慧君,高等教育出版社。免费授课视频 Python编程基础及应用
2.《Python编程基础及应用实验教程》, 陈波,熊心志,张全和,刘慧君,赵恒军,高等教育出版社Python编程基础及应用实验教程
3. 《简明C及C++语言教程》,陈波,待出版书稿。免费授课视频

17.1 汉诺塔问题

法国数学家爱德华·卢卡斯曾转述过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根金刚石柱。印度教的主神梵天在创造世界的时候,在其中一根石柱上从下到上的穿好了由大到小的64块金盘,这就是所谓的汉诺塔 - Hanoi Tower。

按照梵天的命令,不论白天黑夜,总有一个婆罗门僧侣在按照下面的规则移动这些金盘:一次只移动一个盘,不管在哪根柱上,小盘必须在大盘上面。僧侣们预言,当所有的金盘都从梵天穿好的那根柱上移到另外一根柱上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。

17.1.1 求解

如下图所示的5个盘的汉诺塔问题,其总任务是将A柱上的n = 5个盘移至C柱。要实现这个总任务并且保证移盘过程中小盘始终在大盘上面,整个过程分三步实现。第1步:我们必须先将n - 1 = 4个黑盘从A柱移至B柱。在第1步的执行过程当中,为了保证规则的贯彻,显然,必须借助于C柱作为中转柱才能完成。

第1步所做的工作可描述为:借助中转柱C, 将n-1=4个盘从A移至B。
在这里插入图片描述
现在,最大的白盘在A柱上,C柱是空的。可实施第2步:将A柱上的大盘取下,移至C柱。
在这里插入图片描述
接下来,我们要做的是第3步: 借助中转柱A,将B柱上的n - 1 = 4个盘移至C柱。此时,C柱上虽然已经有了一个盘,但由于此盘是最大的,所以只要移动过程中不搬动C柱上的原有大盘,可以忽略其存在。
在这里插入图片描述
现在,我们试图总结一下总任务及其三个子任务:

总任务: 将 n = 5个盘从A柱移至C柱,以B柱为中转柱

不难看出,除了柱子不同,子任务3同子任务1所做的工作是一样的,都是把 n - 1 个盘从一个柱移至另一个柱。同时,子任务1,3与总任务之间也极其相似,除了需要移动的盘子数量差异外。

我们称,将n - 1个盘子从A移至B的汉诺塔问题,与原问题 - 即“将n个盘子从A移至C的汉诺塔问题”的性质完全相同,区别仅在于问题的规模 - 需要移动的盘子数量稍小。我也称为前者是原问题的子问题。

如果我们能将n - 1 = 4个盘子从A移至B,从B移至C,那么n = 5个盘子的汉诺塔问题可解。那么如何求解4个盘子的汉诺塔问题呢?聪明的读者已经有了答案。

子问题: 将 n’ = 4个盘从A柱移至B柱,以C柱为中转柱

下面的图展示了这一过程:
在这里插入图片描述
在这里插入图片描述
上面的分析可以看出,5盘汉诺塔问题可以通过求解4盘汉诺塔问题来解决,4盘汉诺塔问题可以通过求解3盘汉诺塔问题来解决。同理,3盘汉诺塔问题可以通过求解2盘汉诺塔问题来解决,2盘汉诺塔问题可以通过求解一盘汉诺塔问题来解决。而一盘汉诺塔问题,由于问题的规模足够小,可直接解决:把盘从原柱搬至目标柱即可。所以在前表中,我们称其为“简单任务”。

17.1.2 递归算法

根据前一小节描述的算法思想,我们可以写出汉诺塔问题求解的递归算法。

#BasicHanoi.py
def hanoi(n, a, b, c):if n == 1:movements.append(a + " --> " + c)else:hanoi(n - 1, a, c, b)movements.append(a + " --> " + c)hanoi(n - 1, b, a, c)movements = []
hanoi(5, 'A', 'B', 'C')
print("Steps count:",len(movements))
print("The first 3 steps are:", movements[:3])

函数hanoi(n,a,b,c)用于生成以b为中转柱,将n个金盘从a移至c的移盘序列。可以看到,这个递归函数的执行过程跟前节的总任务-子任务分解完全一致。当n == 1时,只有一个盘子,简单任务,直接移盘。如果n > 1,则分解为两个 n - 1 的汉诺塔子问题,以及一个简单移盘任务。子问题的求解以函数递归调用来解决。

上述代码的执行结果如下:

Steps count: 31
The first 3 steps are: ['A --> C', 'A --> B', 'C --> B']

上述结果表明,5盘汉诺塔问题共需要31次移盘。movements列表中按顺序存储了全部的移盘动作。

17.1.3 计算复杂性

使用前小节中的程序,作者尝试计算了n = 5 … 12汉诺塔问题的移盘过程,得到下述移盘次数。
在这里插入图片描述
看起来,似乎n个盘的汉诺塔问题的移盘次数为2n-1。事实上,对移盘次数的数学分析可以证明这个结论。n盘的汉诺塔求解可以拆分成两个n-1盘的汉诺塔求解再加上1次简单移盘。如果用T(n)来表示n盘汉诺塔的移盘次数的话,函数T(n)可使用下述递归定义。
在这里插入图片描述
我们试着把递归函数消解成非递归函数。
在这里插入图片描述
令t = n - 1,有:
在这里插入图片描述
故n盘汉诺塔共需移盘2n-1次。那么,如果梵天规定的是64个金盘的话,总移动次数则为264-1 = 18446744073709551615。如果婆罗门僧侣是个熟练工,1秒挪一个盘,那么1小时可以移3600个盘,1年可移3600 x 24 x 365 = 31536000个盘(忽略闰年误差)。那么,解64盘汉诺塔问题共需要(264-1)/31536000年,即大约5949亿年。看起来,按照当前的人类知识,印度的古老智慧好像高估了地球的预期寿命。

读者不要去尝试计算hanoi(64,’A’,’B’,’C’),显然,在你有限的人生里,是无法完成这件接近“无限”的大事的。而且,因为递归所导致的内存消耗,你有限的计算机内存也排除了这种可能性。

作者是无神论者,上述探讨基于严谨的数学,作者不相信任何人格化的“上帝 ”。

为了帮助更多的年轻朋友们学好编程,作者在B站上开了两门免费的网课,一门零基础讲Python,一门零基础C和C++一起学,拿走不谢!

简洁的C及C++
由编程界擅长教书,教书界特能编程的海洋饼干叔叔打造
Python编程基础及应用
由编程界擅长教书,教书界特能编程的海洋饼干叔叔打造

如果你觉得纸质书看起来更顺手,目前Python有两本,C和C++在出版过程中。

Python编程基础及应用

Python编程基础及应用实验教程
在这里插入图片描述


http://chatgpt.dhexx.cn/article/XIfWhFWR.shtml

相关文章

汉诺塔递归的空间复杂度_学习算法绕不开的~~汉诺塔

大家好,我是老郝。本文就汉诺塔问题向大家阐述递归的思想。 【问题描述】 有三根柱子,最左边的柱子上从大到小放着很多的圆盘,要求把圆盘一个一个的放到最右边的柱子上并且只能小盘子压在大盘子上。(据说古代阿三要他们的和尚把64个圆盘从左到右放一遍,看到最后你就知道阿三…

汉诺塔递归的空间复杂度_【干货】Java算法复杂度

同一问题可用不同算法解决,而一个算法的质量优劣将影响到算法乃至程序的效率。算法分析的目的在于选择合适算法和改进算法。 算法复杂度分为时间复杂度和空间复杂度。其作用: 时间复杂度是度量算法执行的时间长短;而空间复杂度是度量算法所需…

汉诺塔递归问题

汉诺塔问题: 这是一道著名的算法题,也是递归思想的典型体现。 可以总结,当圆盘数为n时,将最下层圆盘和其余上部份所有圆盘看作两个整体,则满足以下步骤: 1、把n-1个圆盘从A经过C移动到B 2、把第n个圆盘从…

汉诺塔递归算法python详细解析图_汉诺塔递归算法的图解(自我总结)

汉诺塔介绍 汉诺塔简单介绍: 有三根相邻的柱子,假定从左到右为A,B,C,A柱子上从下到上按金字塔状叠放着n个不同大小的圆盘,要把所有盘子一个一个移动到柱子B上,并且每次移动同一根柱子上都不能出现大盘子在小盘子上方。…

C#汉诺塔递归算法实现

目录: 一、什么是递归1.先来看一下一个递归的例子2.递归的基本原理 二、汉诺塔问题1.汉诺塔的故事2.回到编程,汉诺塔问题主要就是解决这个问题:3.怎么解决汉诺塔问题要解决汉诺塔问题就要用到递归思想,这里拿四层汉诺塔举例子: 4.…

递归算法 —— Hanoi汉诺塔游戏

前言 博客主页:干脆面la的主页 gitte链接:干脆面la的gitee仓库 刚学习完递归函数接触汉诺塔问题的时候,汉诺塔问题困扰了我很久。博主花了很长时间理解这道题目,因此整理出了用递归解决汉诺塔问题的思路,希望对大家有所…

计算任意位数的黑洞数

黑洞数是指这样的整数: 由这个数字每位数字组成的最大数减去每位数字组成的最小数仍然得到这个数自身。 例如3位黑洞数是495,因为954-459495,4位数字是6174,因为7641-14676174。 def max( x ):data[]while x/1!0:kx%10xx//10data.…

蓝桥杯 黑洞数 解题报告

任意一个5位数,比如:34256,把它的各位数字打乱,重新排列,可以得到一个最大的数:65432,一个最小的数23456。求这两个数字的差,得:41976,把这个数字再次重复上述…

黑洞数—python

黑洞数:黑洞数又称陷阱数,是类具有奇特转换特性的整数。任何一个数字不全相同整数,经有限“重排求差”操作,总会得某一个或一些数,这些数即为黑洞数。“重排求差”操作即把组成该数的数字重排后得到的最大数减去重排后得到的最小数。或者是冰雹原理中的“1”黑洞数 如果有…

6174 黑洞数字

关于6174这个数字的猜想是:从0到9取任意4个不全相同的数字,从大到小排列得到一个4位大数,从小到大排列得到一个4位小数,二者大减小做差,得到一个新的差值,这个值不足4位数补0,重复排列做差的操作…

求4位数的黑洞数

黑洞数又称陷阱数,是类具有奇特转换特性的整数。任何一个数字不全相同整数,经有限“重排求差”操作,总会得某一个或一些数,这些数即为黑洞数。“重排求差”操作即把组成该数的数字重排后得到的最大数减去重排后得到的最小数。或者…

C语言验证黑洞数6174

0x00 问题描述 问题简述:任意选一个四位数(数字不能全相同),把所有数字从大到小排列,再把所有数字从小到大排列,用前者减去后者得到一个新的数。重复对新得到的数进行上述操作,7步以内必然会得到6174。 0x01 代码设计…

黑洞数 C语言

黑洞数也称为陷阱数,又称“Kaprekar问题”,是一类具有奇特转换特性的数。 任何一个各位数字不全相同的三位数,经有限次“重排求差”操作,总会得到495。 最后所得的495即为三位黑洞数。所谓“重排求差”操作即组成该数的数字重排…

黑洞数

黑洞数是指于四位数中,只要数字不完全相同,将数字由大到小的排列减去由小到大的排列。假设一开始选定的数字为,f(),f(),...,f() 用同样的规则继续算下去,最后的结果一定是6174。 比如说一开始选…

python求黑洞数_求解黑洞数

问题描写: 黑洞数又称圈套数,是类具有奇特转换特性的整数。任何1个数字不全相同的整数, 经有限“重排求差”操作,总会得到某1个或1些数,这些数即为黑洞数。 “重排求差”操作即把组成该数的数字重排后得到的最大数减去…

负载均衡之加权轮询算法

在介绍加权轮询算法(WeightedRound-Robin)之前,首先介绍一下轮询算法(Round-Robin)。 一:轮询算法(Round-Robin) 轮询算法是最简单的一种负载均衡算法。它的原理是把来自用户的请求轮流分配给内部的服务器:从服务器1开始,直到服务…

基于HTTP的长轮询实现

Web客户端与服务器之间基于Ajax(http)的常用通信方式,分为短连接与长轮询。 短连接:客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。 在长轮询机制中,客户端像传统轮询一…

Linux轮询操作

Linux设备之非阻塞I/O操作 文章目录 Linux设备之非阻塞I/O操作前言一、接口简介1、select2、poll3、epoll4、总结 二、接口介绍三、代码样例 前言 上一篇讲解了Linux设备的阻塞I/O操作,其原理是利用了把进程挂到等待队列中,等条件满足时再唤醒此进程。本…

短轮询和长轮询

轮询是由客户端每隔一段时间向服务器发出HTTP请求,服务端接收到请求后向客户端返回最新的数据。 客户端的轮询方式一般分为短轮询和长轮询。 短轮询: 一般是由客户端每隔一段时间向服务器发起一次普通HTTP请求。服务端查询当前接口是否有数据更新&#x…

轮询与长轮询

轮询:说白了就是客户端定时去请求服务端, 是客户端主动请求来促使数据更新; 长轮询:说白了 也是客户端请求服务端,但是服务端并不是即时返回,而是当有内容更新的时候才返回内容给客户端,从流程…