带你理解 Hanoi 汉诺塔递归算法

带你理解 Hanoi 汉诺塔递归算法一 由游戏引发的 Hanoi 问题汉诺塔是根据一个传说形成的一个问题 汉诺塔 又称河内塔 问题是源于印度一个古老传说的益智玩具 大梵天创造世界的时候做了三根金刚石柱子 在一根柱子上从下往上按照大小顺序摞着 64 片黄金圆盘 大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上 并且规定 在小圆盘上不能放大圆盘 在三根柱子之间一次只能移动一个圆盘 二 一种数学问题我们

一. 由游戏引发的 Hanoi 问题

汉诺塔是根据一个传说形成的一个问题。汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着 64 片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。

二. 一种数学问题

0000

我们将 Hanoi 问题抽象为一种数学问题。首先给出如下三个柱子 A、B、C,其中 A 柱子上有从上到下从小叠到大的 N 个云盘。现要求将A柱子上的圆盘都移动到 C 柱子上,其中,每次移动都必须满足:

  1. 每次只能移动一个圆盘
  2. 小圆盘上不能放大圆盘

那么针对这个数学问题,就可以提出相关问题:

  1. 移动 N 个圆盘最少需要多少次
  2. 第 M 步移动的是哪个圆盘以及圆盘移动方向
解题:

设总共有 N 个圆盘,Steps表示总移动次数

1.对于问题1

(1)if N == 1

第1次 1号盘 A—->C Steps = 1 次

(2)if N == 2

11号盘 A—->B22号盘 A—->C31号盘 B—->C Steps = 3

(3)if N == 3

11号盘 A—->C ​第22号盘 A—->B ​第31号盘 C—->B ​第43号盘 A—->C ​第51号盘 B—->A ​第62号盘 B—->C ​第71号盘 A—->C Steps = 7

依次往下推,可以发现这样圆盘个数 N 与移动总次数有这样一个规律

1个圆盘的次数 21次方减1 2个圆盘的次数 22次方减1 3个圆盘的次数 23次方减1... ... ... ​n个圆盘的次数 2的n次方减1

所以能得出一个等式关系 : Steps=2n1 S t e p s = 2 n − 1

2.对于问题2

我们使用 数学归纳法 来理解 Hanoi 递归算法。对于递归其实就是方法内部调用自己,同时也一定有一个结束点。学习过汇编语言的伙伴都应该知道,每次的递归调用实际上行的是一种栈操作,这个递归调用其实是方法调用栈的过程。每次调用时从主线程开始调用方法并进行不断地压栈和出栈操作。其中,方法的调入就是将方法压人栈中,方法的结束就是方法出栈的过程。这样可以保证方法调用的顺序流,即当函数出现多层嵌套时,需要从外到内一层层把函数压入栈中,最后栈顶的函数先执行结束(最内层的函数先执行结束)后出栈,再倒数第二层的函数执行结束出栈,到最后,第一个进栈的函数调用结束后从栈中弹出回到主线程,并且结束。

栈的特点是:FIFO(先进后出)。比如一个方法自己调用自己,其中一个调用过程也就是进栈过程:A->A(1)->A(2)->A(3)

在A(3)时满足某种条件得以退出, 回到 A(2), A(2)结束回到A(1), 再回到A, 出栈过程:A(3)->A(2)->A(1)->A

那么,我们现在来看 Hanoi 的递归问题,首先来看当前 Hanoi 问题的递归算法的实现

 move_hanoi.py def move(num,go,to): global i i=i+1 print('第{}步--移动 {} 号圆盘:'.format(i,num), 'move',go,'to',to) def hanoi(num,a,b,c): if num == 1: move(num,a,c) return hanoi(num-1,a,c,b) move(num,a,c) hanoi(num-1,b,a,c) hanoi_move(5,'A','B','C') i=0 

看起来是不是很简单?当时一直都不能懂为什么就是这样的递归,实际上再听老师多次提起后,感觉像是懵懵懂懂假装懂了,具体懂了没懂,还需要试试探讨一番。通过证明可能是很好的办法。

为了证明这中递归算法的合理性,可以采用 数学中归纳法 来理解。对于递归算法问题也不要妄想一开始就追踪整个递归的全程调用。在知乎上有很多非常形象的描述。实际上,如果是对于少于三个盘的 Hanoi 移动来说,其实很好理解。但当数目越来越多时,把这个问题展开来想就变得复杂了,这也是为什么我们需要从层与层之间的交接来理解,而不是展开整个递归。

步骤 圆盘 柱子移动方向 1 1 A -> C

当移动两个盘子,此时 N = 2

步骤 圆盘 柱子移动方向 1 1 A -> B2 2 A -> C3 1 B -> C

当移动三个圆盘时,此时N = 3

步骤 圆盘 柱子移动方向 1 1 A -> C 2 2 A -> B3 1 C -> B 4 3 A -> C 5 1 B -> A 6 2 B -> C 7 1 A -> C 

根据上面的移动情况,我们总结出圆盘移动的规律:

  • 在移动记录中,当盘子的编号和盘子数量相同的时候他们的步骤都是从A移动到C
  • 其他步骤对等

再观察第3个案例中的第 1-3 步 和 第 5-7步

  • 第 1-3 步:目的是从 A 移动到 B。如果我们把 B 当作终点, 那么这里的第 1-3 步理解起来和移动2个圆盘的三个步骤完全相同
    步骤 圆盘 柱子移动方向 B、C 互换 1       1     A  -> C     (A -> B)  2       2     A ->  B     (A -> C)  3       1     C ->  B     (B -> C) 即此时相当于 (XCHG B,C),将 B、C 进行了互换
  • 第 5-7 步:目的是从 B 移动到 C。如果我们把 C 当作终点, 那么这里的 5-7 步理解起来和移动2个圆盘的三个步骤完全相同
    步骤 圆盘 柱子移动方向 B、A 互换 5       1     B  -> A     (A -> B)  6       2     B ->  C     (A -> C)  7       1     A ->  C     (B -> C) 即此时相当于 (XCHG B,A),将 B、A 进行了互换

    那么,我们将以上得到的规律可以总结为

    • 1.只有一个圆盘,Steps=1, 从 A 移动到 C 即结束
    • 2.当有 N 个盘,Steps=2^n-1 为奇数,中间都是动作都是从 A 移动到 C
    • 3.中间动作之上都可以认为是: 从 A 移动到 B
    • 4.中间动作之下都可以认为是: 从 B 移动到 C

我们用伪代码表示以上规律

Function MOVE(N,A,B,C) IF N ==1 THEN Print A;"TO",C ELSE CALL MOVE(N-1,A,C,B);//MOVE(N,A,B,C)中 B、C 互换,N=N-1 Print A;"TO",C CALL MOVE(N-1,B,A,C);//MOVE(N,A,B,C)中 B、A 互换,N=N-1 END IF

这就是对 Hanoi 递归算法的归纳过程

资料引用:

  1. 汉若塔互动百科
  2. 函数调用栈 剖析+图解
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/228403.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月16日 下午7:06
下一篇 2026年3月16日 下午7:06


相关推荐

  • 扣子空间 (Coze Space) 使用入门,邀请码获取指南

    扣子空间 (Coze Space) 使用入门,邀请码获取指南

    2026年3月12日
    4
  • CAN通信协议(一)

    目录目录前言CAN基础知识介绍CAN的特点物理层特征通讯节点波特率及位同步位时序分解波特率帧种类介绍数据帧介绍总结链接地址前言因为工作,需要研究CAN总线。博主的CAN学习参考正点原子和野火的教程。虽然没有买板子,不过对于博主现在来说,感觉开发板都差不多吧!毕竟工作中开发板肯定是不一样的!CAN基础知识介绍CAN是Contr…

    2022年4月4日
    227
  • C++ GetUserName()

    C++ GetUserName()

    2022年3月12日
    44
  • MCP2515调试笔记(一)

    MCP2515调试笔记(一)MSP430 MCP2515 调试笔记 一 nbsp nbsp nbsp nbsp MCP 是 MricoChip 公司生产的一款独立 CAN 控制器 相比恩智浦公司的 SJA1000 它的主要特点是与微控制器之间通过 SPI 方式进行数据交换而不是 SJA1000 的并行方式 这样可以大大减少引脚数量 但在一定程度上也增加了软件的编写复杂度 nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp 本次调试的硬件环境 MSP430F169 MCP2

    2026年3月18日
    2
  • 实验一:双绞线制作

    实验一:双绞线制作双绞线的制作 1 实验目的 nbsp nbsp nbsp nbsp 了解双绞线的制作标准 掌握双绞线的制作过程及应用 2 实验内容 nbsp nbsp nbsp nbsp nbsp 以 100Mb s 的 EIA TIA568B 作为标准规格 制作 100Base T 或 10Base T 网络中计算机与计算机之间的连接双绞线 3 实验环境 nbsp nbsp nbsp nbsp nbsp 双绞线 水晶头若干 压线钳若干 通断议一个 基础知识 nbsp 给出 EIA TIA568A EIA T

    2026年3月20日
    2
  • PORUHBUB.CROWN_ios安卓 testlight /apps/android开发包安装

    PORUHBUB.CROWN_ios安卓 testlight /apps/android开发包安装PORUHBUB.CROWN_ios安卓testlight/apps/android#gym#output#enterip服务器地址https://1024td.com@91.189.91.93enterapp_store_connect_api_keyupload_to_testflightnotification该命令可以及时通知我们当前操作状态;完整配置如下#update_fastlanedefault_platform(:iOS)platform:i..

    2022年10月1日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号