数据结构:递归:汉诺塔问题(Tower of Hanoi)

目录

问题描述

 第一性原理分析

代码实现

第一步:明确函数要干什么

第二步:写好递归的“结束条件”

第三步:写递归步骤 

 🌳 递归调用树

🔍复杂度分析

时间复杂度:T(n) = 2^n - 1

 空间复杂度分析


问题描述

有三个柱子(A, B, C),上面有 n 个大小不等的圆盘,最开始所有圆盘按从大到小顺序堆在柱子 A 上。
目标:将所有圆盘移动到柱子 C,移动时要满足:

  1. 一次只能移动一个盘子;

  2. 任何时刻小盘子不能压在大盘子上。

❓核心问题:

如何将 n 个盘子 从 A 移动到 C,同时只用 B 做辅助,且不违反约束?

 第一性原理分析

🔹1.基础情况(Base Case)

  • n = 1:只有一个盘子,直接从 A → C,一步解决。这是最小子问题。

🔹2. 如果有两个盘子,要怎么动?

设柱子为 A(起始)、B(辅助)、C(目标):

你会这样操作:

  1. 把小盘子从 A → B

  2. 把大盘子从 A → C

  3. 再把小盘子从 B → C

 🔹3. 如果有三个盘子,要怎么动?

步骤 1:移动盘子 1 从 A ➜ C

步骤 2:移动盘子 2 从 A ➜ B

步骤 3:移动盘子 1 从 C ➜ B

步骤 4:移动盘子 3 从 A ➜ C​​​​​​​

步骤 5:移动盘子 1 从 B ➜ A

步骤 6:移动盘子 2 从 B ➜ C​​​​​​​

步骤 7:移动盘子 1 从 A ➜ C​​​​​​​

这就引出一个关键逻辑:

✅ 要移动第 n 个(最大)盘子,必须先把上面的 n-1 个盘子“暂时”搬开。

🧩 移动 n 个盘子的本质是 —— 找出一个“序列”,让我们可以先清掉上面的 n-1 个盘子,再移动第 n 个,然后再恢复那 n-1 个。

换句话说:

  • n-1 个盘子移到辅助柱;

  • 把第 n 个(最大)盘子移到目标柱;

  • 再把那 n-1 个盘子从辅助柱移回来。

这三步操作可以形成递归:

Hanoi(n, A, B, C):1. 移动 n-1 个盘子从 A → B(借助 C)Hanoi(n-1, A, C, B)2. 移动第 n 个盘子从 A → C3. 移动 n-1 个盘子从 B → C(借助 A)Hanoi(n-1, B, A, C)

📐 所以从第一性来看,汉诺塔的“递归”,不是魔法,而是逻辑:

  • 没有任何一步是“看上去神奇的”;

  • 每一个盘子的移动,都必须建立在“先让出空间”的原则上;

  • 这就导致了问题具有自相似性:每一层和上面那一层的问题结构一样;

原理对应在汉诺塔问题的体现
 本质原子操作移动一个盘子,必须遵守限制
 问题的自相似性每个子问题与原问题结构完全一样 ⇒ 递归自然产生
 从底向上构建解决结构不依赖公式,从 n = 1 出发,构建到 n = 2, 3...

代码实现

第一步:明确函数要干什么

我们要写的是一个函数:移动 n 个盘子从柱子 A → 柱子 C,借助柱子 B。

 所以我们需要:

  • 盘子的数量:int n

  • 三个柱子的名字(我们用字符):char from, temp, to

#include <iostream>
using namespace std;// 函数声明:移动 n 个盘子,从 from → to,借助 temp
void hanoi(int n, char from, char temp, char to) {

解释:

  • n:要移动的盘子数

  • from:起始柱

  • temp:中转柱(辅助)

  • to:目标柱

第二步:写好递归的“结束条件”

为什么要加“终止条件”?

如果你不加,递归会无限下去,直到程序崩溃!

    if (n == 1) {cout << "Move disk 1 from " << from << " to " << to << endl;return;}

解释:

  • 如果只剩一个盘子,那就是最简单的情况,直接从 fromto

  • cout 是打印这一步。

第三步:写递归步骤 

    // 1. 把 n-1 个盘子从 from → temp,借助 tohanoi(n - 1, from, to, temp);// 2. 把第 n 个盘子从 from → tocout << "Move disk " << n << " from " << from << " to " << to << endl;// 3. 把 n-1 个盘子从 temp → to,借助 fromhanoi(n - 1, temp, from, to);
}

分析这三步逻辑:

  1. 把顶部的 n-1 个盘子先“挪走”(递归调用自己);

  2. 把第 n 个盘子(最大的)真正地移动到底部(打印出来);

  3. 把刚才挪走的 n-1 个盘子搬回来(递归调用自己)。

完整代码

#include <iostream>
using namespace std;// 递归函数:将 n 个盘子从 from 移动到 to,借助 temp
void hanoi(int n, char from, char temp, char to) {if (n == 1) {cout << "Move disk 1 from " << from << " to " << to << endl;return;}// 第一步:把 n-1 个盘子从 from → temphanoi(n - 1, from, to, temp);// 第二步:移动第 n 个盘子到目标柱cout << "Move disk " << n << " from " << from << " to " << to << endl;// 第三步:把 n-1 个盘子从 temp → tohanoi(n - 1, temp, from, to);
}int main() {int n;cout << "Enter number of disks: ";cin >> n;hanoi(n, 'A', 'B', 'C');return 0;
}

 🌳 递归调用树

我们现在来画出 hanoi(3, A, B, C) 的调用树结构,说明递归是怎么层层展开的。

                            hanoi(3, A, B, C)/         |         \hanoi(2, A, C, B)     Move 3     hanoi(2, B, A, C)/     |     \                       /     |     \hanoi(1,A,B,C)  M2  hanoi(1,C,A,B)   hanoi(1,B,C,A)  M2  hanoi(1,A,B,C)

 标上实际操作编号:

                            hanoi(3, A, B, C)/         |         \hanoi(2, A, C, B)     Move 3     hanoi(2, B, A, C)/     |     \                       /     |     \hanoi(1,A,B,C)  M2  hanoi(1,C,A,B)   hanoi(1,B,C,A)  M2  hanoi(1,A,B,C)/          |         \          |         /          |         \
step1         step2    step3      step4    step5     step6       step7
调用操作内容ABC
hanoi(3, A, B, C)主函数入口[3, 2, 1][][]
hanoi(2, A, C, B)把上面两个盘子从 A ➜ B
hanoi(1, A, B, C)直接移动盘子 1
Move disk 1 A→CStep 1[3, 2][][1]
Move disk 2 A→BStep 2[3][2][1]
Move disk 1 C→BStep 3[3][2, 1][]
Move disk 3 A→CStep 4[][2, 1][3]
hanoi(2, B, A, C)把两个盘子从 B ➜ C
Move disk 1 B→AStep 5[1][2][3]
Move disk 2 B→CStep 6[1][][3, 2]
Move disk 1 A→CStep 7[][][3, 2, 1]

🔍复杂度分析

时间复杂度:T(n) = 2^n - 1

汉诺塔的递归形式是这样的:

T(n) = 2 * T(n - 1) + 1

意思是:

  • 为了移动 n 个盘子:

    • 我们要先移动 n - 1 个盘子(第一次调用);

    • 移动第 n 个盘子(+1 次);

    • 再移动 n - 1 个盘子(第二次调用)。

利用迭代展开式来看:

T(n) = 2*T(n-1) + 1= 2*(2*T(n-2) + 1) + 1 = 4*T(n-2) + 2 + 1= 8*T(n-3) + 4 + 2 + 1= ...= 2^k * T(n - k) + (2^(k-1) + ... + 2 + 1)

 当 k = n-1 时,T(1) = 1,代入得到:

T(n) = 2^(n - 1) * T(1) + (2^(n - 2) + ... + 1)= 2^(n - 1) * 1 + (2^(n - 1) - 1)= 2^n - 1

所以时间复杂度是:⏱️ T(n) = O(2^n)

也就是说:

  • 每增加一个盘子,所需的移动次数翻倍 + 1。

  • 极其不可扩展。

 空间复杂度分析

我们来看递归函数会“开多少层栈”:

void hanoi(int n, char from, char temp, char to)
{if (n == 1) return;hanoi(n - 1, from, to, temp); // 一次递归调用// move...hanoi(n - 1, temp, from, to); // 第二次递归调用
}

递归深度分析:

  • 最大的递归深度就是从 nn-1n-2 → ... → 1

  • 所以最多开 n 层函数栈

所以空间复杂度是:🧠 Space: O(n)

  • 因为递归是深度优先遍历

  • 不会存储所有子问题,只保存当前路径

🕊️ 如果你是“神庙僧侣”,每天只移动 1 次?

汉诺塔在传说中是:64 个金盘子,僧侣每天移动一块。

T(64) = 2^64 - 1 ≈ 1.84 × 10^19 次

即使 1 秒动一次,你也需要:

≈ 5.8 × 10^11 年

而宇宙年龄都才 138 亿年。所以说移动 64 个盘子“永远也完成不了”。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/912798.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/912798.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

synetworkflowopenrestydpdk

一.skynet 1. Skynet 的核心架构是什么&#xff1f;简述其进程与服务模型。 Skynet 采用多进程多服务架构。主进程负责管理和监控&#xff0c;多个工作进程&#xff08;worker&#xff09;负责实际服务运行。每个服务&#xff08;service&#xff09;是一个独立的 Lua 虚拟机&…

【甲方安全视角】安全防御体系建设

文章目录 前言一、云安全防护能力第一阶段:搭建安全防护设施第二阶段:安全防护设施的精细化运营第三阶段:安全运营周报输出二、IT安全防护能力(一)办公网安全设施建设(二)办公网安全运营三、基础安全防护能力(一)物理安全(二)运维安全(三)安全应急响应四、总结前言…

计算机组成原理与体系结构-实验一 进位加法器(Proteus 8.15)

目录 一、实验目的 二、实验内容 三、实验器件 四、实验原理 4.1 行波进位加法器 4.2 先行进位加法器 4.3 选择进位加法器&#xff08;尝试猜测原理&#xff09; 五、实验步骤与思考题 一、实验目的 1、了解半加器和全加器的电路结构。 2、掌握串行进位加法器和并行进…

react+antd Table实现列拖拽,列拉宽,自定义拉宽列

主要插件Resizable&#xff0c;dnd-kit/core&#xff0c;dnd-kit/sortable&#xff0c;dnd-kit/modifiers 其中官网有列拖拽&#xff0c;主要结合Resizable 实现列拉宽&#xff0c;isResizingRef 很重要防止拖拽相互影响 1.修改TableHeaderCell const isResizingRef useRef(…

光照解耦和重照明

项目地址&#xff1a; GitHub - NJU-3DV/Relightable3DGaussian&#xff1a; [ECCV2024] 可重新照明的 3D 高斯&#xff1a;使用 BRDF 分解和光线追踪的实时点云重新照明 可优化参数 gaussians.training_setup(opt) if is_pbr:&#xff1a; direct_env_light.training_setup…

Kafka 运维与调优篇:构建高可用生产环境的实战指南

&#x1f6e0;️ Kafka 运维与调优篇&#xff1a;构建高可用生产环境的实战指南 导语&#xff1a;在生产环境中&#xff0c;Kafka集群的稳定运行和高性能表现是业务成功的关键。本篇将深入探讨Kafka运维与调优的核心技术&#xff0c;从监控管理到性能优化&#xff0c;再到故障排…

AR 地产互动沙盘:为地产沙盘带来变革​

在科技飞速发展的今天&#xff0c;AR&#xff08;增强现实&#xff09;技术应运而生&#xff0c;为解决传统地产沙盘的困境提供了全新的思路和方法。AR 技术&#xff0c;简单来说&#xff0c;是一种将计算机生成的虚拟信息与真实环境相融合的技术。它通过摄像头、传感器等设备获…

端到端自动驾驶系统关键技术

一、感知决策一体化模型架构 单一神经网络整合全流程 端到端神经网络能够直接将传感器输入映射为控制输出&#xff0c;消除了传统模块化架构中感知、规划、控制等独立模块之间的割裂。传统架构中&#xff0c;感知模块负责识别环境信息&#xff0c;决策模块根据感知结果进行路…

Vue Vue-route (2)

Vue 渐进式JavaScript 框架 基于Vue2的学习笔记 - Vue-route重定向和声明式导航 目录 Vue-route路由 重定向 首页默认访问 不存在匹配 声明式导航 路由原理 使用示例 自定义class类 Tag设置 版本4路由 改变 示例 总结 Vue-route路由 重定向 首页默认访问 希望访…

Mabl 基于云端的智能化自动化测试平台

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 </

Linux/Dog

Dog Enumeration nmap 第一次扫描发现系统对外开放了22、80端口&#xff0c;端口详细信息如下 ┌──(kali㉿kali)-[~/Desktop/vegetable/HTB] └─$ nmap -sC -sV -p 22,80 -oA nmap 10.10.11.58 Starting Nmap 7.95 ( https://nmap.org ) at 2025-06-26 03:36 EDT Nmap s…

青少年编程与数学 02-022 专业应用软件简介 01 设计与创意类软件:Adobe Creative Cloud

青少年编程与数学 02-022 专业应用软件简介 01 设计与创意类软件&#xff1a;Adobe Creative Cloud **一、Adobe公司介绍**&#xff08;一&#xff09;Adobe的创立与早期发展&#xff08;二&#xff09;Adobe的市场地位与影响力&#xff08;三&#xff09;Adobe的创新文化 **二…

【亚马逊防关联攻略】多店铺运营如何做好环境隔离?

在亚马逊跨境电商中&#xff0c;多店运营的最大风险是账号关联。亚马逊规定&#xff0c;同一卖家在同一站点只能拥有一个店铺。平台会通过多种方式追踪注册信息、设备和网络环境等&#xff0c;如果发现关联因素&#xff0c;所有关联账号可能被批量封禁&#xff0c;这会导致资金…

She‘s Coming !

#好书推荐《一本书讲透汽车功能安全&#xff1a;标准详解与应用实践》 #功能安全应用指南 #功能安全实践参考宝典 Finally, shes coming ! 她来得有点晚&#xff0c;但 “好饭不怕晚”。 她就是刚出炉的新书《一本书讲透汽车功能安全&#xff1a;标准详解与应用实践》 京东…

如何用废弃电脑变成服务器搭建web网站(公网访问零成本)

文章目录 &#x1f4bb; 如何用废弃电脑变成服务器搭建 Web 网站&#xff08;公网访问零成本&#xff09;一、背景与目标✅ 本文目标&#xff1a; 二、准备工作&#xff08;软硬件需求&#xff09;&#x1f9f1; 1. 硬件需求&#x1f9f0; 2. 软件环境准备 三、快速搭建一个 Fl…

〔从零搭建〕指标体系平台部署指南

&#x1f525;&#x1f525; AllData大数据产品是可定义数据中台&#xff0c;以数据平台为底座&#xff0c;以数据中台为桥梁&#xff0c;以机器学习平台为中层框架&#xff0c;以大模型应用为上游产品&#xff0c;提供全链路数字化解决方案。 ✨杭州奥零数据科技官网&#xf…

Vue3 中watch和computed

Vue 3 中 computed 与 watch 深度解析 在 Vue 3 组合中&#xff0c;响应式工具的类型安全使用至关重要。以下是详细说明 一、watch 侦听器 1. 基础类型监听 <template><div>实际参数1{{count}}</div><div><button click"count">点…

.NET测试工具Parasoft dotTEST:全兼容RMS的测试解决方案

随着项目规模扩大&#xff0c;需求管理变得复杂&#xff0c;如何高效追溯需求与测试的关联性成为一大挑战。Parasoft dotTEST 提供了一套强大的需求追溯解决方案&#xff0c;不仅能自动关联单元测试结果与需求&#xff0c;还能兼容几乎所有需求管理系统&#xff08;RMS&#xf…

基于Jeecgboot3.8.1的vue3版本前后端分离的flowable流程管理平台

初步迁移完成了基于jeecgboot3.8.1的vue3版本的前后端流程管理平台,基于flowable6.8.0,同时支持bpmn流程设计器与仿钉钉流程设计器。 功能类似于3.6.3,但增加了一些以下功能: 1、支持多租户 2、支持并行网关的任意跳转、退回与驳回 3、流程表达式 这里流程表达式定义四…

IP 限流 vs. URI 限流

背景&#xff1a; 昨天调程序的时候遇到了一个 BUG&#xff0c;前端无法将文件正确传给后端&#xff0c;后端报错 EOFException&#xff08;EOF 代表 End Of File&#xff09;就是在程序尝试从一个数据流中读取数据时&#xff0c;发现已经到达了数据流的末尾&#xff0c;但它却…