迷宫问题问题描述:

栈的实现在这篇博客中:https://blog.csdn.net/zj1131190425/article/details/87991662

迷宫是一个矩形区域,有一个出口和入口,迷宫内部包含不能穿越的墙壁和障碍物。

1.用矩阵来描述迷宫。入口是(0, 0), 出口是(m,n),现在需要在迷宫中选找一条路径,穿过迷宫。位置(i,j)=1表示有障碍。0表示无障碍。

思路:

1.出发点处,定义四个方向的坐标偏移量,搜索等四个方向,直到找到一个可行的方向,按照可行的方向移动到下一个位置,将前一个位置坐标压入栈中(保存路径),且将此位置设置为1(放置障碍物,防止往回退的时候又重新搜索这个方向)

2. 如果在某个位置没有找到可行的方向,则将当前这个位置设置为1(这个位置不可再回来),从栈顶弹出一个坐标,作为当前坐标(相当于走回头路),继续搜索其他的方向是否可行。

3. 如此往复

采用自顶向下设计的方法设计代码:

(1)输入迷宫

(2)寻找路径

(3)输出路径

#include <iostream>
#include "E:\back_up\code\c_plus_code\sparseMatrix\external_file\arraystack.h"
#include <string>
using namespace std;// 迷宫
template<typename T>
void print_array(T a[][12])
{for(int i=0; i<12; i++){for(int j=0; j<12; j++){cout << a[i][j] << " ";}cout << endl;}cout << endl;
}class position    // 存储位置坐标
{public:int row;int col;position(){row = 0;col = 0;}position(int row, int col){this->row = row;this->col = col;}void add_offset(position& ps){row += ps.row;col += ps.col;}
}; void find_path(bool map[][12])
{int map_1[12][12];// 保存map()的一个副本for(int i=0; i<12; i++){for(int j=0; j<12; j++){map_1[i][j] = (int)map[i][j];}} // 寻找迷宫的路径arrayStack<position> path; // 存储路径信息// 偏移量position offset[4];// 向右偏移  index=0 offset[0].row = 0;offset[0].col = 1; // 向下偏移  index=1offset[1].row = 1;offset[1].col = 0;// 向左偏移   index=2offset[2].row = 0;offset[2].col = -1;// 向上偏移   index=3offset[3].row = -1;offset[3].col = 0;  position current_position(1,1);   // 初始化当前位置int option = 0;  //初始化选的方向,右,下,左,上=(0,1,2,3)int max_otion = 3;   // 方向的选择范围map[1][1] = 1;   // 在(1,1)位置放置障碍 cout << "current position: " << current_position.row << "  " << current_position.col << endl;while(current_position.row!=10 || current_position.col!=10){int r,c;while(option<=max_otion){r = current_position.row + offset[option].row;c = current_position.col + offset[option].col;if(map[r][c]==0)   // 新的位置可行{break;} option++;}if(option<=max_otion)  // 找到了可行的方向{path.push(current_position); //current_position.add_offset(offset[position]);    // current_position更新 current_position.row = r;    // 移动到新的位置 current_position.col = c;map[r][c] = 1;  // 放置障碍物  避免回退时又选到这个方向 option = 0; } else     // 选择的位置走不通 {if(path.empty()){cout << "The puzzle has no solution" << endl;return;}position next = path.top();path.pop();// 计算返回后的搜索方向:// 按照前面对方向的定义,返回后应该搜索未搜索过的两个方向:// map[currentRow][currentCol] = 1;  // 走不通的位置设置障碍,避免重复搜索 map[current_position.row][current_position.col] = 1;   // 当前的位置是死路 option = 0;current_position = next;   // 浅复制即可 这个类默认的拷贝构造函数 }cout << "(r,c)= " << r << "," << c << endl;}position tmp;while(!path.empty()){// cout << "revise the map" << endl;tmp = path.top();path.pop();map_1[tmp.row][tmp.col] = 2;}// 结果输出 char result[12][12];for(int i=0; i<12; i++){for(int j=0; j<12; j++){if(map_1[i][j]==1){result[i][j]='1';}else if(map_1[i][j]==0){result[i][j]='0';}else{result[i][j]='*';}}}print_array(result);    }int main(int argc, char *argv[])
{//int a[12][12];bool a[][12] = {{1,1,1,1,1,1,1,1,1,1,1,1},{1,0,1,1,1,1,1,0,0,0,0,1},{1,0,0,0,0,0,1,0,1,0,0,1},{1,0,0,0,1,0,1,0,0,0,0,1},{1,0,1,0,1,0,1,0,1,1,0,1},{1,0,1,0,1,0,1,0,1,0,0,1},{1,0,1,1,1,0,1,0,1,0,1,1},{1,0,1,0,0,0,1,0,1,0,1,1},{1,0,1,0,1,1,1,0,1,0,0,1},{1,1,0,0,0,0,0,0,1,0,0,1},{1,0,0,0,0,1,1,1,1,0,0,1},{1,1,1,1,1,1,1,1,1,1,1,1} };//print_array(a);find_path(a);return 0;
}

运行结果:

迷宫问题最短路径

可以使用队列来实现寻找最短路径的操作

首先介绍C++ 实现队列:关于队列的实现参考博客: https://blog.csdn.net/zj1131190425/article/details/88090905,下面的队列是对https://blog.csdn.net/zj1131190425/article/details/88090905中队列的改进,主要是改经了ensureCapacity()函数,因为原来的队列中ensureCapacity()函数有点小的bug.

定义一个队列的基类,queueABC

queueABC.h文件

#ifndef QUEUE_ABC_H
#define QUEUE_ABC_Husing namespace std;
// 定义抽象类
template<typename T>
class queueABC
{public:// virtual ~queue();virtual bool empty() const=0;  // 纯虚函数 只读virtual int size() const=0;    // 返回队列中元素的个数   virtual T& front() = 0;        // 返回队首元素virtual T& back() = 0;         // 返回队尾元素virtual void pop() = 0;        // 删除队首的元素virtual void push(T x) = 0;    // 队尾插入元素
};
#endif

queue.h

#ifndef QUEUE_H
#define QUEUE_H#include <iostream>
#include <algorithm>
#include "E:\back_up\code\c_plus_code\dequeue\external_file\queueABC.h"   // 包含ABC文件
#include "E:\back_up\code\c_plus_code\dequeue\external_file\queueemptyEx.h"   // 包含异常类文件
using namespace std;template<typename T>
class queue : public queueABC<T>
{private:int arrayLength;  // 数组的长度int queueSize;   // 队列中元素的个数int queueFront;   // 队首元素所在的位置int queueBack;    // 队尾元素所在的位置T* element; void ensureArrayLength();   // 进行数组扩容 public:queue(int arrayLength=10);    // 构造函数 ~queue();                     // 析构函数 queue(const queue& q);        // 拷贝构造函数 // ADT bool empty() const;int size() const;T& front();T& back();void pop();void push(T x);void display_queue() const;   // 打印输出队列中的元素 };template<typename T>
queue<T>::queue(int arrayLength)
{this->arrayLength = arrayLength;this->queueSize = 0;this->queueFront = 0;this->queueBack = 0;element = new T[arrayLength];
}template<typename T>
queue<T>::~queue()
{delete [] element;
} template<typename T>
queue<T>::queue(const queue& q)
{arrayLength = q.arrayLength;queueSize = q.queueSize;queueFront = q.queueFront;queueBack = q.queueBack;element = new T[arrayLength];for(int i=0; i<queueSize; i++){element[i] = q.element[i];}
} template<typename T>
bool queue<T>::empty() const
{return queueSize==0;
} template<typename T>
int queue<T>::size() const
{return queueSize;
}template<typename T>
T& queue<T>::front()
{return element[(queueFront+1)%arrayLength];  // queueFront是队首元素的前一个位置,+1是表示队首元素的位置
}template<typename T>
T& queue<T>::back()
{return element[queueBack%arrayLength];    // queueback队尾元素的位置
}/*
template<typename T>
void queue<T>::ensureArrayLength()
{// 如果需要,增加数组长度 if((queueBack+1)%arrayLength==queueFront)   // 环形的数组 {T* old;old = element;//delete element;// arrayLength = arrayLength*2;   // 增加分配的内存长度 element = new T[2*arrayLength]; // 环形数组重新布局// 先将数组复制过来//更新关于数组复制int index_tmp;for(int i=0; i<queueSize; i++){index_tmp = (queueFront+1+i)%arrayLength;element[index_tmp] = old[index_tmp];}delete old;// 重新布局  // 分为三种情况:1.queuefront=0; queuefront==arrayLength-1; else;int pre_start = queueFront%arrayLength;  // 队列首元素的前一个位置 if(pre_start==0){// 移动所有的数组元素 for(int i=0; i<queueSize; i++){element[2*arrayLength-1-i] = element[(queueBack%arrayLength)-i];} queueFront = queueFront + arrayLength;queueBack = queueBack + arrayLength;} else if(pre_start==arrayLength-1)   // arrayLength还是原来的值 {// 不用移动数组元素,之更改front queueFront = queueFront + arrayLength; }else{// 移动第二段的元素:int element_to_move = arrayLength-1-(queueFront%arrayLength);  // 计算第二段需要移动的元素的数量 for(int i=0; i<element_to_move; i++){element[2*arrayLength-1-i] = element[queueBack%arrayLength-i];} queueFront = queueFront + arrayLength;}arrayLength = arrayLength*2;   // 更新arrayLength        }// 添加一个动态减少内存的函数
}
*/template<typename T>
void queue<T>::ensureArrayLength()
{if((queueBack+1)%arrayLength==queueFront)   // 环形的数组 {T* new_element = new T[2*arrayLength];int start = (queueFront+1)%arrayLength;if(start<2)   // 没有形成环{copy(element+start, element+start+arrayLength-1, new_element);    // 复制操作 } else   // 形成环{copy(element+start, element+arrayLength, new_element);copy(element, element+queueBack+1, new_element+arrayLength-start);} queueFront = 2*arrayLength-1;queueBack = arrayLength-2;arrayLength *= 2;delete[] element;element = new_element;}
}// push()操作:
template<typename T>
void queue<T>::push(T x)
{ensureArrayLength();     // 先保证数组长度满足条件queueSize++;//queueBack = (queueBack+1)%arrayLength;//element[queueBack] = x;   queueBack++;element[queueBack%arrayLength] = x;
} //pop()操作
template<typename T>
void queue<T>::pop()
{if(empty())throw queueEmptyException(0); queueFront++;queueSize--;// element[queueFront].~T;
} template<typename T>
void queue<T>::display_queue() const
{//int tmp = queueFront;// int start_pos = (tmp+1)%arrayLength;if(empty()){cout << "The queue is empty!" << endl;return;}for(int i=0; i<queueSize; i++){cout << element[(queueFront+1+i)%arrayLength] << " ";}cout << endl;
}#endif 

自定义的异常类:

queueemptyException:

// 自定义异常类
#ifndef QUEUE_EMPTY_EXCEPTION
#define QUEUE_EMPTY_EXCEPTION
#include <stdexcept>
#include <iostream>
using namespace std;class queueEmptyException : public runtime_error
{private:int queueSize;public:queueEmptyException(int queueSize) : runtime_error("The queue empty!"){this->queueSize = queueSize;}void display_error_info(){cout << "The queue size is " << queueSize << endl;}
};
#endif

寻找最短路径的算法思路:

从上面的迷宫中,找一条从入口到出口的最短路径,要有两个过程:

1. 一个是距离标记过程

2. 另一个是路径标记过程

在距离标记过程中,把能从入口到达的相邻位置标记为1,然后把从编号为1可到达的相邻位置标记为2(表示与入口相距为2),直到到达出口或者没有可标记的相邻位置为止。

在路径标记过程中,从出口开始,首先移动到比出口的编号小1的位置,再从当前位置移动到比其编号小1的位置上,直到到达起点为止,这便是最短的路径

3.按照上述思路编写代码实现:

main.cpp

#include <iostream>
#include "E:\back_up\code\c_plus_code\dequeue\external_file\queue.h"
using namespace std;// 迷宫
template<typename T>
void print_array(T **a, int size)
{for(int i=0; i<size; i++){for(int j=0; j<size; j++){cout << a[i][j] << " ";}cout << endl;}cout << endl;
}class position    // 存储位置坐标
{public:int row;int col;position(){row = 0;col = 0;}position(int row, int col){this->row = row;this->col = col;}/*void add_offset(position& ps){row += ps.row;col += ps.col;}*/}; void findPath(int** map, int mapSize=10)
{// 这里默认起始点为(0,0),终点为(9,9)// 给地图添加围墙:int** new_map = new int*[mapSize+2];for(int i=0; i<mapSize+2; i++){new_map[i] = new int[mapSize+2];} for(int i=0; i<mapSize+2; i++){for(int j=0; j<mapSize+2; j++){    if(i==0 || i==mapSize+2-1){new_map[i][j] = 1;  // 增加行围墙 }else if(j==0 || j==mapSize+2-1)   //增加列围墙 {new_map[i][j] = 1;}else  // 保存地图 {new_map[i][j] = map[i-1][j-1]; } }}// print_array(map, mapSize);cout << "原始地图: " << endl;print_array(new_map, mapSize+2);// 初始化偏移量position offset[4];// 向右偏移  index=0 offset[0].row = 0;offset[0].col = 1; // 向下偏移  index=1offset[1].row = 1;offset[1].col = 0;// 向左偏移   index=2offset[2].row = 0;offset[2].col = -1;// 向上偏移   index=3offset[3].row = -1;offset[3].col = 0;    position current_position(1,1);   // 初始化当前位置position end_position(10,10);new_map[current_position.row][current_position.col] = 2;  // 这里距离标记从2开始,实际距离等于标号-2int direction_number = 4;   // 一个方格相邻位置的个数 position neighbor;queue<position> q;    // 队列,用于存放标记的位置 while(true){// 给相邻位置做标记for(int i=0; i<direction_number; i++){neighbor.row = current_position.row + offset[i].row;neighbor.col = current_position.col + offset[i].col;if(new_map[neighbor.row][neighbor.col]==0)  // 可标记的位置{new_map[neighbor.row][neighbor.col] = new_map[current_position.row][current_position.col]+1; // 标记 if(neighbor.row==end_position.row && neighbor.col==end_position.col){break;   // 标记完成 } q.push(neighbor); } }if(neighbor.row==end_position.row && neighbor.col==end_position.col){break;   // 到达 }if(q.empty())    // 迷宫无解; {cout << "The puzzle has no solution" << endl;return;}current_position = q.front();q.pop(); }//cout << "标记完的矩阵: " << endl; //print_array(new_map, 12); // 构造路径;int pathLength = new_map[end_position.row][end_position.col]-2;  // 路径的长短 // position* path = new position[pathLength];queue<position> q_path;   // 存储路径 current_position =  end_position;   // 从终点回溯for(int i=pathLength-1; i>=0; i--){// path[i] = current_position;   q_path.push(current_position);    // 当前的位置放入队列中 for(int j=0; j<direction_number; j++){neighbor.row = current_position.row + offset[j].row;neighbor.col = current_position.col + offset[j].col;if(new_map[neighbor.row][neighbor.col] == i+2){break;}} //测试 // cout << "current position: " << current_position.row << ',' << current_position.col << endl;current_position = neighbor; } /*    测试代码 position tmp; while(!q_path.empty()){tmp = q_path.front();cout << "path: " << tmp.row << "," << tmp.col << endl;q_path.pop();}*//*   测试代码 for(int i=0; i<pathLength; i++){cout << "path: " << path[i].row << "," << path[i].row << endl;}*/// 输出结果 char** result = new char*[mapSize+2];    // 创建一个新的矩阵保存可视化结果 for(int i=0; i<mapSize+2; i++){result[i] = new char[mapSize+2];}// 初始化:position tmp;while(!q_path.empty()){tmp = q_path.front();result[tmp.row][tmp.col] = '*';q_path.pop();} for(int i=0; i<mapSize+2; i++){for(int j=0; j<mapSize+2; j++){if(result[i][j] != '*' && new_map[i][j]==1){result[i][j] = '1';}if(result[i][j] != '*' && (new_map[i][j]==0 || new_map[i][j]>1)){result[i][j] = '0';}}}   // 输出迷宫路径cout << "最短路径: " << pathLength << endl; cout << "迷宫路径如下所示: " << endl;print_array(result, mapSize+2); } int main(int argc, char *argv[])
{   int map_size = 10;int input_map[10][10] = {{0,1,1,1,1,1,0,0,0,0},{0,0,0,0,0,1,0,1,0,0},{0,0,0,1,0,1,0,0,0,0},{0,1,0,1,0,1,0,1,1,0},{0,1,0,1,0,1,0,0,0,0},{0,1,0,0,0,1,0,1,0,1},{0,1,0,0,0,1,0,1,0,1},{1,0,0,0,0,0,0,1,0,0},{0,0,0,0,1,1,1,1,0,0} };// 数据转换 int** map_in = new int*[map_size];for(int i=0; i<map_size; i++){map_in[i] = new int[map_size];}for(int i=0; i<map_size; i++){for(int j=0; j<map_size; j++){map_in[i][j] = input_map[i][j];}}// 将原始地图转换为指针的形式findPath(map_in, map_size);    return 0;
}

算法的运行结果如下图所示:

---------------------------------------------------end----------------------------------------------------------

数据结构与算法 迷宫问题相关推荐

  1. 数据结构与算法——迷宫问题

    课程名称:数据结构与算法 设计题目:迷宫问题 已知技术参数和设计要求: 问题描述: 以一个m*n的长方阵表示迷宫,0和1分别表示迷宫中的通路和障碍.迷宫问题要求求出从入口(1,1)到出口(m,n)的一 ...

  2. 数据结构与算法 迷宫夺宝 C语言

    迷宫夺宝 1.1 题目要求 一个N x N的矩阵代表了一个迷宫,迷宫中每个房间由以下三种数字的一种来表示:     0 代表房间安全,是可以通过的.     1 代表房间中有奖励物品,玩家可以拿到奖励 ...

  3. 数据结构和算法(十)递归-迷宫游戏

    1. 数据结构和算法(十)递归-迷宫游戏 1.1 迷宫游戏   今天做一个简单的迷宫游戏,用二维数实现地图,让程序自动寻路的小游戏. 1.2 简单的迷宫 简单的迷宫 用二维数实现地图,找路策略:[右- ...

  4. python中栈的描述是_数据结构与算法:Python语言描述 栈和队列.ppt

    数据结构与算法:Python语言描述 栈和队列 迷宫问题 迷宫问题的特点: 存在一集可能位置,一些位置相互连通,一步可达 一个位置可能连通若干位置,出现向前探查的多种可能(有分支) 目标是找到一条路径 ...

  5. 数据结构与算法—图论之dfs、bfs(深度优先搜索、宽度优先搜索)

    文章目录 前言 邻接矩阵和邻接表 深度优先搜索(dfs) 宽度(广度)优先搜索(bfs) 总结与比较 前言 在有向图和无向图中,如果节点之间无权值或者权值相等,那么dfs和bfs时常出现在日常算法中. ...

  6. 数据结构与算法(Python)– 回溯法(Backtracking algorithm)

    数据结构与算法(Python)– 回溯法(Backtracking algorithm) 1.回溯法 回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条 ...

  7. 数据结构与算法之递归系列

    本文来自一个不甘平凡的码农 写在前边 几个月之前就想写这样一篇文章分享给大家,由于自己有心而力不足,没有把真正的学到的东西沉淀下来,所以一直在不断的在自学. 然后又用了一个星期的时间去整理.分类,才有 ...

  8. PTA 数据结构与算法题目集(中文)

    一:数据结构与算法题目(中文版) 7-2 一元多项式的乘法与加法运算 (20 分) 7-3 树的同构 (25 分) 7-4 是否同一棵二叉搜索树 (25 分) 7-6 列出连通集 (25 分)(详解) ...

  9. 【数据结构与算法】广度优先遍历(BFS) 深度优先遍历(DFS)

    一. 搜索算法 深度优先搜索和广度优先搜索是最暴力的图的搜索算法.算法的目标是,给定一张图,一对初始和终止节点,找到两节点之间的节点路径.(代码均是找到两个节点之间的路径) 广度优先搜索是一层一层搜索 ...

最新文章

  1. 教你如何用阿里canal
  2. 数据库安全:不只是DAM
  3. 做演员是圆梦 做生意学会面对现实
  4. 在后台增加一个查询条件
  5. 再读simpledb 之 SQL语句解析(1)
  6. android桌面adw,ADW Launcher
  7. PostgreSQL数据库从入门到精通
  8. 一个普通人的震后十年
  9. 深度解读央行数字货币 DCEP
  10. 农业银行透支卡和信用卡什么关系?2019年农业银行透支卡透支额度?
  11. 江西赣州计算机应用中心,赣州计算机应用与维修专业学校
  12. 【二】Centos 7.6下载与安装
  13. fiddler重放请求
  14. MT25QU128 (flash) 简介
  15. CRNN论文翻译——中英文对照
  16. SICP:费马小定理与素数检测
  17. Win10 UEFI安装
  18. LLVM指令选择中的模式定义方法
  19. Java eight
  20. python tello_Tello-Edu无人机:如何用Python代码捕捉图像

热门文章

  1. 分布式系统认证方案_分布式系统介绍_Spring Security OAuth2.0认证授权---springcloud工作笔记134
  2. STM32工作笔记0029---认识电路原理图中的VCC,VDD,VEE,VSS
  3. IOS学习笔记07---C语言函数-scanf函数
  4. Android学习笔记---22_访问通信录中的联系人和添加联系人,使用事物添加联系人...
  5. gcc 安装在服务器的问题总结
  6. mac上解决中文乱码, arara实现LaTex多命令执行, LaTeXiT法文界面转英文
  7. VC/MFC中的CComboBox控件使用详解
  8. 无人驾驶(ncnn学习)
  9. python编程(类的释放)
  10. 内购订单进行二次处理_游戏内购要涨价?谷歌效仿苹果:安卓内购抽成30%