当前位置: 首页 > article >正文

数据结构:汉诺塔问题的递归求解和分析

递归方法求解该类问题,是一种简单的思维方法,通常比使用迭代方法更简单。但是,递归方法也有劣势。此处以典型的汉诺塔问题(Tower of Hanoi)为例给予说明。

汉诺塔是根据一个传说形成的数学问题,最早是由法国数学家爱德华·卢卡斯提出。

有三根杆子 A,B,C 。A 杆上有 N 个 ( N > 1 ) (N>1) (N>1) 穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至 C 杆:

  1. 每次只能移动一个圆盘;
  2. 大盘不能叠在小盘上面。

问:如何移动?最少要移动多少次?

下面链接是一个汉诺塔问题的交互操作程序,读者可以通过操作,尝试解决此问题。https://www.mathsisfun.com/games/towerofhanoi.html

汉诺塔问题,以及之前遇到过的阶乘、斐波那契数列等,都是分治思想的典型应用。

对于汉诺塔问题,解决方法如下,如图 5.1.1 所示。

在这里插入图片描述

图 5.1.1 汉诺塔问题的求解过程

假设 A 柱上最初的盘子总数为 n n n

  • n = 1 n=1 n=1 时,只要将编号为 1 的圆盘从 A 直接移至 C 上即可。
  • 否则,执行如下三步:
    1. 用 C 柱做过渡,将 A 柱上的 ( n − 1 ) (n-1) (n1) 个盘子移到 B 柱上;
    2. 将 A 柱上最后一个盘子直接移到 C 柱上;
    3. 用 A 柱做过渡,将 B 柱上的 ( n − 1 ) (n-1) (n1) 个盘子移到 C 柱上。

由上述求解过程可知,汉诺塔问题符合分治算法的递归求解要求。

【算法步骤】

  1. 如果 n = 1 n=1 n=1 ,则直接将编号为 1 的圆盘从 A 移到 C,递归结束。
  2. 否则:
    • 递归,将 A 上编号为 1 至 n − 1 n-1 n1 的圆盘移到 B,C 做辅助塔;
    • 直接将编号为 n 的圆盘从 A 移到 C;
    • 递归,将 B 上编号为 1 至 n − 1 n-1 n1 的圆盘移到 C,A 做辅助塔。

【算法描述】

//定义搬动操作函数 move(A, n, C) ,将编号为 n 的圆盘
// 从 A 移到 C。
//用全局变量 m 对搬动次数计数
int m = 0;
void move(char A, int n, char C){
    cout << ++m <<"," << n << "," << A << "," << C << endl;
}

void Hanoi(int n, char A, char B, char C){
    //将 A 上的 n 个圆盘移到 C 上,B 做辅助塔
    if (n == 1) move(A, 1, C); //将编号为 1 的圆盘从 A 移到 C
    else {
        Hanoi(n-1, A, C, B); //将 A 上不编号为 1 至 n-1 的圆盘移到 B ,C 做辅助塔
        move(A, n, C);  //编号为 n 的圆盘从 A 移到 C
        Hanoi(n-1, B, A, C); //将 B 上编号为 1 至 n-1 的圆盘移到 C,A 做辅助塔
    }
}

【算法分析】

假设圆盘数量为 n n n 时,移动圆盘的时间复杂度为 T ( n ) T(n) T(n) ;圆盘数量为 ( n − 1 ) (n-1) (n1) 时时间复杂度 T ( n − 1 ) T(n-1) T(n1) 。根据算法,要将 n − 1 n-1 n1 个圆盘从 A 移到 B(借助 C),然后将这些圆盘从 B 移到 C(借助 A)。再加上将编号为 n 的圆盘从 A 移到 C 所花费的常数时间(用 c c c 表示)则得到递推公式:
T ( n ) = 2 T ( n − 1 ) + c T(n)=2T(n-1)+c T(n)=2T(n1)+c
根据递推公式,有:
T ( n ) = 2 T ( n − 1 ) + c = 2 [ 2 T ( n − 2 ) + c ] + c = 2 2 T ( n − 2 ) + [ 2 + 1 ] c = 2 2 [ 2 T ( n − 3 ) + c ] + [ 2 + 1 ] c = 2 3 T ( n − 3 ) + [ 2 2 + 2 + 1 ] c   ⋮ = 2 n − 1 T ( 1 ) + [ 2 n − 2 + ⋯ + 2 0 ] c \begin{split} T(n)&=2T(n-1)+c=2[2T(n-2)+c]+c \\&=2^2T(n-2)+[2+1]c=2^2[2T(n-3)+c]+[2+1]c \\&=2^3T(n-3)+[2^2+2+1]c \\&~\vdots \\&=2^{n-1}T(1)+[2^{n-2}+\cdots+2^0]c \end{split} T(n)=2T(n1)+c=2[2T(n2)+c]+c=22T(n2)+[2+1]c=22[2T(n3)+c]+[2+1]c=23T(n3)+[22+2+1]c =2n1T(1)+[2n2++20]c
显然 T ( 1 ) = c T(1)=c T(1)=c

上述汉诺塔问题算法的时间复杂度是 O ( 2 n ) O(2^n) O(2n) ,即指数阶的时间复杂度。

在第 2 章(因为本文是我编写的《数据结构》考研复习讲义中的节选,所以,读者在阅读的时候,如果遇到类似的表述,勿要深究)已经研究过这种指数阶时间复杂度,在一般情况下, 无法用于解决实际问题,不是一个有效的算法。

对于汉诺塔问题的时间复杂度分析,也可以通过计算移动盘子的次数得到,借用前面给出的交互演示程序和算法,可知:

圆盘数量 n n n移动圆盘次数
1 1 = 2 1 − 1 1=2^1-1 1=211
2 3 = 2 2 − 1 3=2^2-1 3=221
3 7 = 2 3 − 1 7=2^3-1 7=231
⋮ \vdots ⋮ \vdots
n 2 n − 1 2^{n}-1 2n1

因此时间复杂度为 O ( 2 n ) O(2^n) O(2n)


http://www.kler.cn/a/612055.html

相关文章:

  • 部分 Bash 内置命令的详解
  • 企业网站源码HTML成品网站与网页代码模板指南
  • 学习记录-Ajax-自封装axios函数
  • RAMS(区域大气建模系统)评估土地利用/覆被变化的气候与水文效应
  • 【Django】教程-3-数据库相关介绍
  • NVIDIA Megatron Core:大规模语言模型训练与部署框架详解
  • [250325] Claude AI 现已支持网络搜索功能!| ReactOS 0.4.15 发布!
  • 英语不好,可以考取Oracle OCP认证吗?
  • HO与OH差异之Navigation三
  • Android第六次面试总结(自定义 View与事件分发)
  • Unity Shader编程】之FallBack
  • CSS3:现代Web设计的魔法卷轴
  • 行为型——责任链模式
  • 本地文生图使用插件(Stable Diffusion)
  • MybatisPlus(SpringBoot版)学习第五讲:条件构造器和常用接口
  • poetry install --with aws
  • SQL语言的安全开发
  • 网易邮箱DolphinScheduler迁移实战:从部署到优化,10倍效率提升的内部经验
  • 数据结构6-图
  • 数制——FPGA