数据结构-栈和队列的应用

目录

  • 前言
  • 一、栈的应用
  • 二、队列的应用(农夫过河问题)
    • 2.1 问题描述
    • 2.2 算法选择
    • 2.3 算法精化
    • 2.4 算法实现
    • 2.5 问题结果
  • 总结

前言

本篇文章使用两个例子说明栈和队列的应用,
对于迷宫问题,使用栈实现深度优先策略解决迷宫问题;
对于农夫过河问题,使用队列实现广度优先策略解决农夫过河问题。

一、栈的应用

二、队列的应用(农夫过河问题)

2.1 问题描述

一个农夫带着一只狼、一只羊和一颗白菜,身处河的南岸。农夫要把这些东西全部运到河的北岸。问题是农夫只有一条小船,船小到只能容下农夫和一件物品,当然,船只有农夫能撑。另外,因为狼能吃羊,而羊能吃白菜,所以,农夫不能留下羊和狼或者羊和白菜单独在河一边,自己离开。好在狼属于食肉动物,它不吃白菜。请问农夫该采取什么方案,才能将所有的东西安全运过河呢?

2.2 算法选择

求解这个问题的最简单的方法是逐步进行试探。每一步都在前一步选择基础上搜素下一步的所有可能的状态。用计算机实现上述系统搜索过程,可以采用两种不同的策略,一种是广度优先搜索(breadth first);另一种是深度优先搜索(depth first)。实现广度优先搜索的工具是队列;实现深度优先搜索的工具是栈。本节讨论队列的应用,所以重点介绍广度优先搜索策略。
广度优先搜索的思想就是,在搜索过程中,总是首先搜索下面一步的所有可能情况,然后再进一步考虑更后面的各种情况。要实现广度优先搜索,一般都采用队列作为辅助结构,把每一步所有可能达到的状态都列举出来,放在这个队列中,然后顺序取出来分别进行处理,在处理中又再把下一步的情况全部放在队列里。由于队列的操作原则是先进先出,所以,只有在前一步的所有情况都处理完后,才能开始后面一步各情况的处理。
以遍历二叉树为例,使用广度优先搜索策略,进行层序遍历。
在这里插入图片描述

图2.1 广度优先遍历二叉树

2.3 算法精化

要模拟农夫过河问题,首先需要选择一个对问题中每个角色的位置进行描述的方法。一个很方便的方法是用4位二进制数顺序分别表示农夫、狼、白菜和羊的位置。例如,用0表示农夫或某物品在河的南岸,1表示在河的北岸。因此,整数5(其二进制表示为0101)表示农夫和白菜在河的南岸,而狼和羊在北岸。这时,农夫不在,因此狼会把羊吃掉,所以是一种不安全的状态。问题的初始状态是整数0(其二进制为0000);而问题的终结状态是整数15(其二进制表示为1111)。
在这里插入图片描述

图2.2 二进制位置表示图

用整数location表示用上述方法描述的状态,可以用下面的4个函数从上述状态得到每个角色所在位置的代码。函数返回值为真(1)表示农夫或物品的位置在河的北岸,否则在南岸。

//农夫过河问题
//个体判断函数
/*	四位二进制数分别表示农夫,狼,白菜,羊的位置0 表示在南岸  1 表示在北岸初始状态 location = 0000(二进制) 表示农夫,狼,白菜,羊都位于河的南岸使用按位 & 操作,取出每个位置的信息,例如 location & 0x08 取出农夫的位置信息
*///取出农夫位置信息
int farmer(int location)
{return (0 != (location & 0x08));
}//取出狼位置信息
int wolf(int location)
{return (0 != (location & 0x04));
}//取出白菜位置信息
int cabbage(int location)
{return (0 != (location & 0x02));
}//取出羊位置信息
int goat(int location)
{return (0 != (location & 0x01));
}

此外,还应该分析问题中的所有角色构成的状态,确定其中那些状态是安全的,哪些是不安全的。因为,单独留下白菜和羊或单独留下狼和羊在某一岸是不安全的,所以安全状态的判断可以使用下面的函数实现。

//安全状态的判断函数
/*不能单独留下狼和羊,例如 location = 0101 是一种不安全的状态不能单独留下白菜和羊,例如 location = 1100 是一种不安全的转态安全返回 1不安全返回 0
*/int safe(int location)
{//判断羊和白菜是否单独if ((goat(location) == cabbage(location)) && (farmer(location) != goat(location))){return 0;}//判断狼和羊是否单独if ((wolf(location) == goat(location)) && (farmer(location) != goat(location))){return 0;}return 1;   //其他状态安全
}

2.4 算法实现

完成了上面的准备工作后,现在的问题变成:从初始状态二进制0000出发,寻找一种全部由安全状态构成的、能够实现的状态变迁序列(序列中的每状态都可以从前一状态通过农夫带东西划船过河到达),到达最终状态二进制1111.为避免不必要的重复,在序列中不应该出现重复的状态。
根据广度优先搜索的思想,算法中需要使用一个整数队列moveTo,把搜索过程中每一步所有可能到达的状态都保存起来。队列中的每个元素表示可以安全到达的中间状态。
另外,使用一个整数数组rooute记录已被访问过的各个状态,以及已被发现的能够到达这些状态的前驱状态。由于在这个问题中需要列举的所有状态(二进制0000~1111)一共16种,所以route数组只需要使用16个元素。route的每个元素初始化为-1,每当在队列中加入一个新的状态时,就把route中以该状态作下标的元素的值改为达到这个状态的前一转态的下标值。所以数组的第i个元素不仅记录了状态i是否已经被访问过,同时对于以及被访问过的状态,还保存了这个状态的前驱状态下标。算法结束后,可以利用route数组元素的值生成一个正确的路径。
在这里插入图片描述

图2.3 route数组

代码实现如下:

//农夫问题求解/*从初始状态二进制0000出发,寻找一种全部由安全状态构成、能够实现的状态变迁序列(序列中的每个状态都可以从前一状态通过农夫带东西划船过河到达)到达最终的状态1111。为避免不必要的重复,在序列中不应该出现重复的状态整数队列moveTo:把搜索过程中每一步所有可能到达的状态都保存起来。队列中的每个元素表示可以安全到达的中间状态整数数组route:用于记录已被访问过的各个状态,以及已被发现的能够到达这些状态的前驱状态由于在这个问题中需要列举的状态(二进制0000~1111)一共16种,则数组长度大小为16每个数组的元素值初始化为-1每当在队列中加入一个新的状态时,就把route中以该状态做下标的元素的值改为达到这个状态的下标值数组的第i个元素不仅记录状态i是否已被访问过,同时对于已被访问过的状态,还保存了这个状态的前驱状态算法结束后,可以利用route数组元素的值生成一个正确的状态路径
*/void farmerProblem()
{int movers, location, newlocation;int route[16];				//用于记录已考虑的状态路径struct SeqQueue moveTo;		//用于记录可以安全到达的中间状态initSeqQueue(&moveTo);		//初始化队列enSeqQueue(&moveTo, 0x00);	//初始状态二进制0000入队for (int i = 0; i < 16; i++)//初始化数组route{route[i] = -1;}route[0] = 0;while (!isEmptySeqQueue(&moveTo) && (route[15] == -1)){getQElemSeqQueue(&moveTo, &location);	//取出队头状态为当前状态QElemType e;deSeqQueue(&moveTo, &e);//循环值依次表示羊、白菜、狼、农夫的移动情况//movers的值用二进制表示依次为0001(羊)、0010(白菜)、0100(狼)、1000(农夫)for (movers = 1; movers <= 8; movers <<= 1){if ((0 != (location & 0x08)) == (0 != (location & movers))) //农夫与移动的物品在同一岸{// 0x08 | movers 得到的结果表明农夫或物品应该在船上,物品无法单独过河// location ^ (0x08 | movers) 把坐船过河的农夫与物品的状态翻转newlocation = location ^ (0x08 | movers);			//计算新状态if (safe(newlocation) && route[newlocation] == -1)	//新状态安全且未处理{route[newlocation] = location;					//记录旧状态且作为新状态的前驱enSeqQueue(&moveTo, newlocation);				//将新状态入队}}}}if (route[15] != -1){printf("The reverse path is :\n");for (location = 15; location >= 0; location = route[location]){printf("The location is : %d\n", location);if (location == 0){exit(0);}}}else{printf("No solution\n");}
}

注意:这里实现队列的代码已省略,感兴趣可查看文章:https://blog.csdn.net/pyc68/article/details/145093486?spm=1001.2014.3001.5501

算法开始时,把初始状态为0(表明人和物都在南岸)放入队列中。while循环时,只要队列不为空便取出队头元素,for循环用于列举所有可以移动的角色(包括农夫本身,用movers表示),for循环的增量表达式里使用了左移位操作,循环值依次为1、2、4、8,分别表示羊、白菜、狼和农夫的移动情况。由于在每一次移动时,农夫都必须改变状态,所以只有农夫与被移动的东西在同一岸时,农夫才可以将其带走。当然,农夫可以什么都不带,单独过河。将变量movers与二进制0x08进行按位异或运算,所得结果为1,表明相应的农夫或物品应该在船上,再将原有状态与这个结果进行一次按位异或运算,得到移动后的一个新状态。最后检验新状态是否安全,是否未被处理过。如果成立,就确认这个状态转换可行(把这个状态放入队列中,并且修改route数组的值)

2.5 问题结果

图2.4标出了送入队列的各个状态(位置)和广度优先搜索的顺序编号。
通过图2.4得出一条从0000到达1111的路径:
0000-1001:农夫把羊从南岸带到北岸
1001-0001:农夫独自从北岸回到南岸
0001-1011:农夫把白菜从南岸带到北岸
1011-0010:农夫把羊从北岸带回南岸
0010-1110:农夫把狼从南岸带到北岸
1110-0110:农夫独自从北岸回到南岸
0110-1111:农夫把羊从南岸带到北岸

在这里插入图片描述

图2.4 广度优先搜索的结果和顺序图

总结

农夫过河问题完整代码:https://gitee.com/PYSpring/data-structure/tree/master/queue_code

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

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

相关文章

Acwing-基础算法课笔记之基础算法(差分)

Acwing-基础算法课笔记之基础算法&#xff08;差分&#xff09; 一、一维差分1、差分的概念2、差分思想 二、二维差分操作流程 一、一维差分 1、差分的概念 对于一个给定的序列a&#xff0c;它的差分序列b定义为&#xff1a; b [ 1 ] a [ 1 ] b[1]a[1] b[1]a[1]&#xff0c…

SkyWalking 10.1.0 实战:从零构建全链路监控,解锁微服务性能优化新境界

文章目录 前言一、集成SkyWalking二、SkyWalking使用三、SkyWalking性能剖析四、SkyWalking 告警推送4.1 配置告警规则4.2 配置告警通知地址4.3 下发告警信息4.4 测试告警4.5 慢SQL查询 总结 前言 在传统监控系统中&#xff0c;我们通过进程监控和日志分析来发现系统问题&…

【动态规划】风扫枯杨,满地堆黄叶 - 9. 完全背包问题

本篇博客给大家带来的是完全背包问题之动态规划解法技巧. &#x1f40e;文章专栏: 动态规划 &#x1f680;若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅&#x1f680; 要开心要快乐顺…

MyBatis的工作流程是怎样的?

大家好&#xff0c;我是锋哥。今天分享关于【MyBatis的工作流程是怎样的&#xff1f;】面试题。希望对大家有帮助&#xff1b; MyBatis的工作流程是怎样的&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 MyBatis 的工作流程可以分为几个主要的步骤&…

python-leetcode 25.环形链表

题目&#xff1a; 给定一个链表的头节点head,判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪next指针再次到达&#xff0c;则链表中存在环。为了表示给定链表中的环&#xff0c;评测系统内部使用整数pos来表示链表尾连接到链表中的位置&#xff08;…

瑞芯微开发板/主板Android调试串口配置为普通串口方法 深圳触觉智能科技分享

本文介绍瑞芯微开发板/主板Android调试串口配置为普通串口方法&#xff0c;不同板型找到对应文件修改&#xff0c;修改的方法相通。触觉智能RK3562开发板演示&#xff0c;搭载4核A53处理器&#xff0c;主频高达2.0GHz&#xff1b;内置独立1Tops算力NPU&#xff0c;可应用于物联…

Datawhale 组队学习 Ollama教程 task1

一、Ollama 简介 比喻&#xff1a;Ollama 就像是一个“魔法箱子”&#xff0c;里面装满了各种大型语言模型&#xff08;LLM&#xff09;。你不需要懂复杂的魔法咒语&#xff08;配置&#xff09;&#xff0c;只需要轻轻一按&#xff08;一条命令&#xff09;&#xff0c;就能让…

错误报告:WebSocket 设备连接断开处理问题

错误报告&#xff1a;WebSocket 设备连接断开处理问题 项目背景 设备通过自启动的客户端连接到服务器&#xff0c;服务器将设备的 mac_address 和设备信息存入 Redis。前端通过 Redis 接口查看设备信息并展示。 问题描述 设备连接到服务器后&#xff0c;前端无法立即看到设…

vscode关闭后如何恢复在远程服务器的终端程序运行界面

网上有很多种解决方案&#xff0c;我觉得比较好用的是screen。这里先介绍screen的安装和使用办法&#xff1a; 通过 conda 安装 screen是比较方便的方式&#xff0c;可以按照以下步骤操作&#xff1a; 通过 Conda 安装 screen 打开终端或命令行工具。确保你已经激活了 Conda 环…

vulnhub 靶场 —— NullByte

免责声明 本博客文章仅供教育和研究目的使用。本文中提到的所有信息和技术均基于公开来源和合法获取的知识。本文不鼓励或支持任何非法活动&#xff0c;包括但不限于未经授权访问计算机系统、网络或数据。 作者对于读者使用本文中的信息所导致的任何直接或间接后果不承担任何…

React 初级教程

一、React 简介 React 是由 Facebook 开发的开源 JavaScript 库,用于构建用户界面(UI)。特点: 声明式编程:通过描述 UI 应该是什么样子(而不是操作 DOM)来构建界面。组件化:将 UI 拆分为独立可复用的组件。跨平台:支持 Web(React)、移动端(React Native)、VR 等。…

使用 meshgrid函数绘制网格点坐标的原理与代码实现

使用 meshgrid 绘制网格点坐标的原理与代码实现 在 MATLAB 中&#xff0c;meshgrid 是一个常用函数&#xff0c;用于生成二维平面网格点的坐标矩阵。本文将详细介绍如何利用 meshgrid 函数生成的矩阵绘制网格点的坐标&#xff0c;并给出具体的代码实现和原理解析。 实现思路 …

git tag的使用方法

1.添加tag git tag 2.添加tag并添加信息 git tag -a -m “your message” 3.查看tag git tag 4.推到远端 git push origin 5.推送所有本地标签到远程仓库 git push origin --tags 6.删除tag git tag -d 7.切换到某一个tag git checkout

【STM32系列】利用MATLAB配合ARM-DSP库设计FIR数字滤波器(保姆级教程)

ps.源码放在最后面 设计IIR数字滤波器可以看这里&#xff1a;利用MATLAB配合ARM-DSP库设计IIR数字滤波器&#xff08;保姆级教程&#xff09; 前言 本篇文章将介绍如何利用MATLAB与STM32的ARM-DSP库相结合&#xff0c;简明易懂地实现FIR低通滤波器的设计与应用。文章重点不在…

使用mermaid画流程图

本文介绍使用mermaid画流程图&#xff0c;并给出几个示例。 背景 目前&#xff0c;除有明确格式要求的文档外&#xff0c;笔者一般使用markdown写文档、笔记。当文档有图片时&#xff0c;使用Typora等软件可实时渲染&#xff0c;所见即所得。但如果文档接收方没有安装相关工具…

C# ASP.NET核心特性介绍

.NET学习资料 .NET学习资料 .NET学习资料 在当今的软件开发领域中&#xff0c;C# ASP.NET凭借其强大的功能和丰富的特性&#xff0c;成为构建 Web 应用程序的重要技术之一。以下将详细介绍 C# ASP.NET的核心特性。 多语言支持 ASP.NET 支持多种语言进行开发&#xff0c;这使…

使用Hexo部署NexT主体网站

一.使用git提交文件 参考&#xff1a; 从零开始搭建个人博客&#xff08;超详细&#xff09; - 知乎 致谢&#xff01; 第一种&#xff1a;本地没有 git 仓库 直接将远程仓库 clone 到本地&#xff1b;将文件添加并 commit 到本地仓库&#xff1b;将本地仓库的内容push到远程仓…

12.项目结构

后端结构 ruoyi-admin 项目启动的入口 提供了两种启动方式 1.RuoYiApplication基于springboot,内置tomcat,直接运行。 2.RuoYiServletInitializer将springboot项目打成一个war包,用外置的servlet容器来运行。 通用功能的controller 后台登录相关的、权限控制相关的、数据字…

cursor如何使用到150次以及解决cursor限制问题

cursor白嫖免费版限制问题解决以后经常遇到只使用了50次额度就被限制了&#xff0c;软件提示you reached your trial。 解决方法 使用cursor的老版本&#xff0c;因为老版本有agent和normal可以切换&#xff0c;通过切换通往世界的IP&#xff0c;重启软件或者切换点几次agent和…

mmdetection3d环境部署

安装python库 pip install torch1.9.1cu111 torchvision0.10.1cu111 torchaudio0.9.1 -f https://download.pytorch.org/whl/torch_stable.html pip install mmengine pip install mmcv-2.0.0rc4-cp38-cp38-manylinux1_x86_64.whl pip install mmdet>3.0.0,<3.1.0 cd m…