栈应用实例--迷宫问题
来源:互联网 发布:h5切水果游戏源码 编辑:程序博客网 时间:2024/05/21 17:48
调试环境:vs2015+win10
众所周知,栈是一个非常常见且有用的数据结构。
这里讲解一下利用栈来实现迷宫问题。
使用递归实现
假设有一迷宫
其中:1代表墙;0代表路径
为简化编程,假设左边界0处为迷宫入口,下边界0处为迷宫出口库。
分析问题:
- 创建一个结构体,表示在迷宫的坐标
- 从文件中读取迷宫
- 获取迷宫路径,需要判断是否可走,将走过的地方标记为2
代码实现:
#include<assert.h>#include<stack>#include<iomanip>#include<iostream>using namespace std;struct Pos { int _row; //行 int _col; //列 Pos& operator+(Pos& pos) { //重载加法运算 _row += pos._row; _col += pos._col; return *this; }};//获取地图void GetMaze(int* maze) {//为什么不传二维数组,因为二维数组在传参时需要声明个数,这样传参简单实用 FILE* fp = fopen("MazeMap1.txt", "r"); //读取地图文件 assert(fp); // 断言 size_t i = 0; char c = 0; while ((c = fgetc(fp)) != EOF) { //将从文件读取的一个字符赋值给c,并判断是否是文件尾 if (c == '1' || c == '0') { //c如果是墙或是路 *(maze + i) = c - '0'; //满足就将该字符存入数组 ++i; } }}//打印地图void PrintMaze(int* maze, size_t N) { assert(maze); for (size_t i = 0; i < N; ++i) { //利用二维的方式访问maze for (size_t j = 0; j < N; ++j) { cout << maze[i*N + j] << " "; //打印该节点的值 } cout << endl; //换行 }}//判断是否可走bool CheckIsAccess(int* maze, size_t N, Pos pos) { assert(maze); if ((pos._col >= 0) && (pos._col < N) && (pos._row >= 0) && (pos._row < N)) {//判断是否不为边界 if (maze[pos._row*N + pos._col] != 1) { //判断是否是墙 if (maze[pos._row*N + pos._col] == 0) { //判断是否是路 return true; //满足返回true } } } return false; //不满足返回false}//获取地图路径void GetMazePath(int* maze, size_t N, Pos entry) { assert(maze); Pos test[4] = { { -1,0 },{ 0,1 },{ 1,0 },{ 0,-1 } };//声明一个Pos数组,分别表示向上,右,下,左偏移一个单位 Pos cur = entry; //复制当前节点为cur maze[cur._row*N + cur._col] = 2; //将该节点赋值为2,表示来过 for (int i = 0; i < 4; ++i) { //分别判断该节点的4个方向是否可走 cur = entry; //每次循环时,回复到初始节点 cur = cur + test[i]; //加上偏移量 if (CheckIsAccess(maze, N, cur)) { //判断该节点的该方向是否可走 GetMazePath(maze, N, cur); //满足则进行递归调用,则可以遍历完所有的路径 } }}//测试函数void TestMaze() { int* maze = new int[100]; //利用指针声明一个一维数组,方便传参 Pos entry = { 2,0 }; //设置迷宫入口点 GetMaze(maze); //获取地图内容 PrintMaze(maze, 10); //打印迷宫,此次为初始化时的迷宫 GetMazePath(maze, 10, path, entry);//获取迷宫路径 PrintMaze(maze, 10); //打印迷宫,此为遍历完所有路的迷宫地图}//主函数int main(){ TestMaze(); //调用迷宫测试函数 return 0;}
运行结果:
使用栈实现迷宫
递归调用思路简单,编写起来也很容易,接下来我们将递归改成非递归,就需要用到栈。
同样是上面的那个地图,采用STL里面的栈,实现迷宫
思路与上面大体相同
使用上面的代码,则只需要修改GetMazePath()函数和TestMaze()函数
代码实现:
//获取地图路径void GetMazePath(int* maze, size_t N, stack<Pos>& path, Pos entry) { assert(maze); Pos test[4] = { { -1,0 },{ 0,1 },{ 1,0 },{ 0,-1 } };//上,右,下,左 Pos cur = entry; //赋值当前节点为cur path.push(cur); //将该节点压入栈中 maze[cur._row*N + cur._col] = 2; //将该节点赋值为2,标记为走过 while (!path.empty()) { //循环条件为栈是否为空 int i = 0; for (i = 0; i < 4; ++i) { cur = path.top(); //每次循环时,将cur的值复位为栈顶元素 cur = cur + test[i]; //cur改为新坐标 if (CheckIsAccess(maze, N, cur)) { //判断新坐标是否可走 maze[cur._row*N + cur._col] = 2; //如果可走,将该节点赋值为2 path.push(cur); //并将该节点压入栈中 break; //如果可以通则break,如果此路最终不能达到终点,返回时在判断该坐标点的四周是否可走,即采用深度优先的思想走迷宫 } } if (i == 4) { //如果i为4,即说明该坐标的四周都无可走路,则弹栈 path.pop(); } }}//测试函数void TestMaze() { stack<Pos> path; //声明一个路径栈 int* maze = new int[100]; //声明一个数组 Pos entry = { 2,0 }; //设置初始入口点 GetMaze(maze); //获取地图 cout << "初始化地图" << endl; PrintMaze(maze, 10); //打印初始化地图 path.push(entry); //将入口压栈 maze[entry._row * 10 + entry._col] = 2; //将入口赋值为2,表示来过 GetMazePath(maze, 10, path, entry); //获取路径 PrintMaze(maze, 10); //打印迷宫地图}
运行结果:
使用栈查找迷宫最短路
上面讲解的方法只是遍历了所有路,如果需要返回是否找到通路,可以使用栈来保存路径所经过的坐标
当迷宫具有多条通路时,就需要返回最短路径,所以我们的地图也升级成为了下图
如图所示,在迷宫中有一条回路,即有多条路径可以成为通路
如果需要找到最短路径,不仅需要保存通路的路径,还要保证是最短的,这就需要使用两个栈,一个保存当前通路的路径,另一个保存最短路径
思路也有一点变化
- 获取地图
- 以起点开始,标记为2,此后每走一步,标记自加,存进数组
- 判断是否为最短路
代码上还是只需要改动两个关键的函数即可
代码实现:
stack<Pos> check; //声明一个全局栈,用来保存最短路径//打印地图void PrintMaze(int* maze, size_t N) { assert(maze); for (size_t i = 0; i < N; ++i) { for (size_t j = 0; j < N; ++j) { cout << setw(3) << maze[i*N + j]<<" "; //使用setw()函数,使输出方便观察 } cout << endl; }}//判断是否可走bool CheckIsAccess(int* maze, size_t N, Pos pos,stack<Pos> path) { assert(maze); if ((pos._col >= 0) && (pos._col < N) && (pos._row >= 0) && (pos._row < N)) { //判断是否越界 if (maze[pos._row*N + pos._col] != 1) { //判断是否为墙 if (maze[pos._row*N + pos._col] == 0) { //判断是否为未走过的路 return true; } if (( maze[pos._row*N + pos._col] - maze[path.top()._row*N + path.top()._col])>1) { //判断该节点与栈顶元素的差值是否大于1,如果为真,即说明该节点曾走过 return true; } } } else { if(!(pos._row==2 && pos._col==-1)) //如果不是入口点的左节点,将path的元素赋给check check = path; } return false; //如果不满足上述条件,即表明该节点四周都不能走}//获取地图路径void GetMazePath(int* maze, size_t N, stack<Pos>& path, Pos entry,int js) { assert(maze); Pos test[4] = { {-1,0},{0,1},{1,0},{0,-1} };//上,右,下,左 Pos cur = entry; path.push(cur); //压栈 maze[cur._row*N + cur._col] = js; //当前节点的值 for (int i = 0; i < 4; ++i) { cur = entry; cur = cur + test[i]; if (CheckIsAccess(maze, N, cur,path)) { //判断是否可以走 GetMazePath(maze, N, path, cur, js + 1); //每次递归调用时js+1 } } path.pop(); //如果本节点的4个方向都探测完后,将此节点弹栈}//测试函数void TestMaze() { stack<Pos> path; int* maze= new int[100]; Pos entry = { 2,0 }; GetMaze(maze); PrintMaze(maze, 10); path.push(entry); GetMazePath(maze, 10, path, entry, 2); //初始的时候js赋值为2 PrintMaze(maze, 10); path.pop(); //最后将迷宫入口点弹栈}
运行结果:
如运行结果所示,数字按照每条路依次递增,简单明了。
如果想知道具体路径可以查看check里面的值
这里就简单的实现了一下迷宫问题。
1 0
- 栈应用实例--迷宫问题
- 【栈应用】迷宫问题
- 栈应用----迷宫问题
- 迷宫问题(栈的应用)
- 栈的应用--迷宫问题
- 迷宫问题(栈的应用,二维数组表示迷宫)
- <数据结构>栈的应用三:迷宫问题
- 栈的应用之迷宫问题
- 栈的应用——迷宫问题
- 栈的应用-迷宫问题-数据结构
- 栈的应用之迷宫问题
- 迷宫问题——栈的应用
- 栈的应用——迷宫问题
- 栈的应用Ⅱ--迷宫问题
- 栈和队列的应用:迷宫问题
- 数据结构之 栈应用---老鼠迷宫问题
- 16 - 12 - 21 栈的应用实例(走迷宫)
- 栈应用-走迷宫
- 基于线程池和NIO技术构建高效的多协议Android通讯框架(转)
- ecplise文件之间的关系
- java.util.Collections.unmodifiableList()方法实例
- JavaScript之路开篇--介绍
- mvp架构初体验之介绍与实践
- 栈应用实例--迷宫问题
- Python爬虫 爬取Google Play 100万个App的数据,并入库到数据库 scrapy框架
- Storm解读之路(二、基本 Java-API 篇)
- 【Codeforces 734 C Anton and Making Potions 】+ 思维
- 记录tip
- HTML 事件触发javascript
- 歪门邪道 Leetcode 463 Island Perimeter
- Leetcode1.Two Sum+LeetCode15.3Sum+LeetCode18. 4Sum【K-Sum问题】
- 剑指offer---对称的二叉树