算法入门<二>:分治算法之汉诺塔问题及递归造成的栈溢出

1、分治算法

  分治(divide and conquer),全称分而治之,是一种非常重要且常见的算法策略。分治通常基于递归实现,包括“分”和“治”两个步骤。

  • (划分阶段):递归地将原问题分解为两个或多个子问题,直至到达最小子问题时终止。
  • (合并阶段):从已知解的最小子问题开始,从底至顶地将子问题的解进行合并,从而构建出原问题的解。

一个问题是否适合使用分治解决,通常可以参考以下几个判断依据。

  • 问题可以分解:原问题可以分解成规模更小、类似的子问题,以及能够以相同方式递归地进行划分。
  • 子问题是独立的:子问题之间没有重叠,互不依赖,可以独立解决。
  • 子问题的解可以合并:原问题的解通过合并子问题的解得来。

  分治不仅可以有效地解决算法问题,往往还可以提升算法效率。在排序算法中,快速排序、归并排序、堆排序相较于选择、冒泡、插入排序更快,就是因为它们应用了分治策略。

2、汉诺塔问题

2.1 传说

  大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。 简化后类似如下:
在这里插入图片描述

2.2 分治策略

  解决汉诺塔问题的分治策略:将原问题f(n)划分为两个子问题f(n-1)和一个子问题f(1),并按照以下顺序解决这三个子问题。

  1. 将n-1个圆盘借助 C 从 A 移至 B 。
  2. 将剩余1个圆盘从 A 直接移至 C 。
  3. 将n-1个圆盘借助 A 从 B 移至 C 。

  对于这两个子问题 f(n-1),可以通过相同的方式进行递归划分,直至达到最小子问题 f(1)。而f(1)的解是已知的,只需一次移动操作即可。
在这里插入图片描述

2.3 代码实现

/* 求解汉诺塔问题 f(i) *//* 移动一个圆盘 */
void move(vector<int>& src, vector<int>& tar) 
{// 从 srcA 顶部拿出一个圆盘int pan = src.back();src.pop_back();// 将圆盘放入 tarC 顶部tar.push_back(pan);
}void dfs(int nSize, vector<int>& srcA, vector<int>& bufB, vector<int>& tarC,int& nMoveTimes)
{// 若 srcA 只剩下一个圆盘,则直接将其移到 tarCif (nSize == 1){nMoveTimes++;move(srcA, tarC);return;}// 子问题 f(i-1) :将 srcA 顶部 i-1 个圆盘借助 tarC 移到 bufBdfs(nSize - 1, srcA, tarC, bufB, nMoveTimes);// 子问题 f(1) :将 srcA 剩余一个圆盘移到 tarCmove(srcA, tarC);// 子问题 f(i-1) :将 bufB 顶部 i-1 个圆盘借助 srcA 移到 tarCdfs(nSize - 1, bufB, srcA, tarC, nMoveTimes);
}void solveHanota(vector<int>& A, vector<int>& B, vector<int>& C, int& nMoveTimes)
{int nSize = A.size();// 将 A 顶部 n 个圆盘借助 B 移到 Cdfs(nSize, A, B, C, nMoveTimes);
}int main()
{int nObject = 25;vector<int> vecObject;for (int i = nObject; i > 0; i--){vecObject.push_back(i);}int nMoveTimes = 0;vector<int> objectB;vector<int> objectC;solveHanota(vecObject, objectB, objectC, nMoveTimes);std::cout << "放置圆盘" << nObject << "个,共计需要移动" << nMoveTimes << "次!" << endl;return 0;
}
放置圆盘25个,共计需要移动16777216次!

2.4 代码漏洞

  当盘子数量为64的话,一共需要移动约1800亿亿步(18,446,744,073,709,551,615),才能最终完成整个过程。即使借助于计算机,假设计算机每秒能够移动100万步,那么约需要18万亿秒,即58万年。将计算机的速度再提高1000倍,即每秒10亿步,也需要584年才能够完成。所以上述解法无法处理大数据量问题

3、递归导致栈溢出

  递归算法在数学问题上会经常出现,但运用不当会出问题。有的是运算时间太长如上面的汉诺塔问题,有的则是栈溢出,例如下面代码。我们着重说一下栈溢出问题。

// 递归求和函数当n=4750会出现栈溢出问题
void Sum(int& nSum, int n)
{if (n == 0){return;}nSum += n;n--;Sum(nSum, n);
}
// 斐波那契数列 0,1,1,2,3,5,8…… 递归树 时间复杂度高 会卡死
unsigned int fib(int n)
{if (n == 1 || n == 2){return n - 1;}return fib(n - 2) + fib(n - 1);
}
// 阶乘 时间复杂度高 卡死
unsigned int factorialRecur(unsigned int n)
{if (n == 0){return 1;}int count = 0;for (int i = 0; i < n; i++){count += factorialRecur(n - 1);}return count;
}

3.1 为什么会栈溢出?

  计算机的内存可以分为三个区域:栈区,堆区,静态区。它们在存储使用时遵循不同的规则,并且存储的内容也不同。其中栈内存速度最快但空间很小一般只有几兆M大小,而我们每一次递归时,上一次的递归程序仍然没有结束,也就是上一次递归的函数仍然占据着内存栈区的空间; 递归调用函数次数太多栈就会溢出。

在这里插入图片描述

3.2 解决方式

  对于栈溢出的问题一般通过减少递归的层数来解决。比如下面的求和问题。

// 递归求和函数当n=4750会出现栈溢出问题
void Sum(int& nSum, int n)
{if (n == 0){return;}nSum += n;n--;Sum(nSum, n);
}// 迭代求和  可正常计算
unsigned int Sum(int n)
{int nSum = 0;for (int a = 1; a <= n; a++){nSum += a;}return nSum;
}

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

PyCharm 2024新版图文安装教程(python环境搭建+PyCharm安装+运行测试+汉化+背景图设置)

名人说&#xff1a;一点浩然气&#xff0c;千里快哉风。—— 苏轼《水调歌头》 创作者&#xff1a;Code_流苏(CSDN) 目录 一、Python环境搭建二、PyCharm下载及安装三、解释器配置及项目测试四、PyCharm汉化五、背景图设置 很高兴你打开了这篇博客&#xff0c;如有疑问&#x…

小浪助手:下载学浪视频的最佳助手

小浪助手我已经打包好了,有需要的自己下载一下 学浪下载器链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;1234 --来自百度网盘超级会员V10的分享 1.首先解压好我给大家准备好的压缩包 2.打开小浪助手.exe 3.选择一种登录方式&#xff0c;扫码登录或者手机号…

【办公类-26-02】20240423 UIBOT学分自动评价(自动登录、评价和退出,全自动)

背景需求&#xff1a; 我想用UIBOT自动模拟鼠标&#xff0c;登录每位老师的账户&#xff0c;进入评价区域&#xff0c;自动选择7次“满意”&#xff0c;输入1次“无”&#xff0c;然后提交。 C Dim objExcelWorkBook,arrayRet,iRet,temp,iPID,hWeb,dictRet,XobjExcelWorkBook …

警惕虚假宣传:GPT-4.0免费领取真相揭秘

警惕虚假宣传&#xff1a;GPT-4.0免费领取真相揭秘 在人工智能技术飞速发展的今天&#xff0c;尤其是OpenAI推出的GPT-4.0成为技术前沿的焦点&#xff0c;不少不法分子也开始借机进行欺诈。网络上出现了大量声称“免费领取GPT-4.0”的虚假信息&#xff0c;这不仅误导了公众&am…

latex使用bib引用参考文献时,正文编号顺序乱序解决办法,两分钟搞定!

一、背景 用Latex写文章时&#xff0c;使用bib添加参考文献是一种最为简便的方式。但有的期刊模板&#xff0c;如机器人顶会IROS&#xff0c;会出现正文参考文献序号没按顺序排列的情况&#xff0c;如下图所示。按理说文献[4]应该是文献[2]&#xff0c;[2]应该是[3]&#xff0…

计米功能块(CODESYS 完整ST源代码)

1、S7-1200测速计米功能块 S7-1200高速计数器编码器线速度测量(独立测速FB计米FB)_s7-1200高速计数器编程实例-CSDN博客文章浏览阅读646次。线速度工程中有很多采集方法&#xff0c;这里不再细述。博途PLC的高速计数器编程应用大家可以查看下面相关应用文章&#xff1a;计米轮…

代码随想录算法训练营DAY46|C++动态规划Part8|139.单词拆分、多重背包理论基础、背包问题总结篇

文章目录 139.单词拆分思路CPP代码 多重背包理论基础处理输入把所有个数大于1的物品展开成1个开始迭代&#xff0c;计算dp数组代码优化 背包问题总结篇 139.单词拆分 力扣题目链接 文章讲解&#xff1a;139.单词拆分 视频讲解&#xff1a;你的背包如何装满&#xff1f;| LeetCo…

70.网络游戏逆向分析与漏洞攻防-角色与怪物信息的更新-整理与角色数据更新有关的数据

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果 现在的代码都是依据数据包来写的&#xff0c;如果看不懂代码&#xff0c;就说明没看懂数据包…

神经网络中常见的激活函数:理解与实践

神经网络中常见的激活函数&#xff1a;理解与实践 在神经网络中&#xff0c;激活函数是一个非常重要的组成部分&#xff0c;它为神经元引入了非线性特性&#xff0c;使得神经网络可以拟合各种复杂的函数关系。本文将介绍9种常见的激活函数&#xff0c;包括它们的概述、公式以及…

【开源设计】京东慢SQL组件:sql-analysis

京东慢SQL组件&#xff1a;sql-analysis 一、背景二、源码简析三、总结 地址&#xff1a;https://github.com/jd-opensource/sql-analysis 一、背景 开发中&#xff0c;无疑会遇到慢SQL问题&#xff0c;而常见的处理思路都是等上线&#xff0c;然后由监控报警之后再去定位对应…

unity入门——按钮点击了却无法调用函数

查阅了一番都没有解决问题&#xff0c;最后发现问题是由button的Onclick()事件绑定了代码脚本而不是游戏对象导致的。 如果Onclick()事件绑定的是代码脚本&#xff0c;则下拉框里没有函数&#xff0c;但是点击MonoScript后能手动填入函数名&#xff08;本以为这样就能实现调用…

JavaScript百炼成仙自学笔记——2

一、循环遍历&#xff1a; 方式一 for(var i0;i<10;i){console.log(i); }方式二 var i 0; while(i < 100){console.log(i);i; }细看代码就是 先定义变量i&#xff0c;再执行{}中的代码&#xff0c;最后改循环变量的值 二、遍历 什么事遍历&#xff1f; 什么时候会用…

SpringBoot中阿里OSS简单使用

官方文档:Java跨域设置实现跨域访问_对象存储(OSS)-阿里云帮助中心 1.pom中引入依赖 <dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.15.1</version> </dependency> 如…

图床搭建GitHub+PicGo+jsdelivr(CDN)+Typora(内附加速工具)

目录 安装PicGo GitHub配置与加速器 配置PicGo 使用typroa 安装PicGo PicGo是一个用于上传图片的客户端&#xff0c;支持拖拽上传、剪贴板上传&#xff0c;功能十分方便。 下载地址&#xff1a; https://github.com/Molunerfinn/PicGo/releases 个人网盘自取版本2.4.0…

高颜值管理系统界面,我敢保证你肯定看不够,看了又看。

有不少老铁&#xff0c;还坚持10年前的老思路&#xff0c;总觉得B端管理系统颜值不颜值不重要&#xff0c;关键是好用就行&#xff0c;这就犯了二元论的错误。 谁说高颜值的管理系统&#xff0c;就不好用了呢&#xff1f;高颜值和易用性冲突吗&#xff1f;我看未必吧。看看大厂…

SSL certificate problem: unable to get local issuer certificate【鸿蒙报错已解决】

文章目录 项目场景:问题描述原因分析:解决方案:此Bug解决方案总结Bug解决方案寄语项目场景: 最近也是遇到了这个问题,看到网上也有人在询问这个问题,本文总结了自己和其他人的解决经验,解决了【SSL certificate problem: unable to get local issuer certificate】的问…

制作一个 rpm 软件包

首发日期 2024-04-30, 以下为原文内容: 本文以 ibrus (艾刷, 胖喵拼音 ibus 接口模块) 为例, 介绍 rpm 软件包的制作过程. 相关文章: 《发布 AUR 软件包 (ArchLinux)》 https://blog.csdn.net/secext2022/article/details/136803790《多种双拼方案的实现》 https://blog.csdn.…

STM32(c语言基础)

1.硬件部分&#xff1a;按键&#xff0c;传感器 传感器模块&#xff1a;光敏电阻&#xff0c;热敏电阻&#xff0c;红外接收管 光敏电阻&#xff1a;光线越强&#xff0c;光敏电阻的阻值就越小&#xff1b; 热敏电阻&#xff1a;温度越高&#xff0c;热敏电阻的阻值越小&…

【全网首发】2024五一数学建模ABC题保奖思路(后续会更新)

一定要点击文末的卡片哦&#xff01; 1&#xff09;常见模型分类 机理分析类&#xff1a;来源于实际问题&#xff0c;需要了解一定的物理机理&#xff0c;转化为优化问题。 运筹优化类&#xff1a;旨在找到使某个目标函数取得最大或最小值的最优解,对于机理要求要求不高&…

Linux下安装snaphu

1、官网下载安装包 2、解压&#xff0c;移动文件夹到/usr/local/下 3、在/usr/local/下创建man&#xff0c;在man下创建man1文件夹 4、进入到snaphu的src文件夹里&#xff0c;执行sudo make&#xff0c;如果报错 在这个 Makefile 中&#xff0c;-arch x86_64 是 macOS 特定的…