学习了数据结构第二章栈后,实验作业是解决简单的迷宫问题。假设迷宫只有一个入口和出口,默认其大小是10x10。
使用栈来记录位置坐标,首先是坐标类和栈的简单定义
const int N = 10; //迷宫大小是10x10
const int maxsize = 100; //数组长度上限,因为默认迷宫大小是10x10,所以路径最多有100个
class Position {
private:
int x; //横坐标
int y; //纵坐标
public:
Position(); //默认坐标(0,0)
Position(int x, int y); //有参构造函数
void setpos(int x, int y); //设置坐标
int getx(); //获得行坐标
int gety(); //获得列坐标
void print(); //以坐标的形式打印
Position left(); //返回向左移动后的坐标
Position right(); //向右
Position up(); //向上
Position down(); //向下
bool is_obstacle(bool map[][N]); //判断该点是否是障碍
bool overstep(bool map[][N]); //判断是否越界
};
class Stack {
private:
int top; //栈顶“指针”
Position path_[maxsize]; //存储路径的数组
public:
Stack();
bool isempty(); //判空
void push(Position c); //入栈
Position pop(); //出栈
Position gettop(); //返回栈顶元素
};
其次是各自的实现
#include <iostream>
using std::cout;
using std::endl;
#include "stack.h"
Position::Position() {
x = 0;
y = 0;
}
Position::Position(int x, int y) {
this->x = x;
this->y = y;
}
void Position::setpos(int x, int y) {
this->x = x;
this->y = y;
}
int Position::getx() {
return x;
}
int Position::gety() {
return y;
}
void Position::print() {
cout << "(" << x << "," << y << ")";
}
Position Position::left() {
return Position(x, y - 1);
}
Position Position::right() {
return Position(x, y + 1);
}
Position Position::up() {
return Position(x - 1, y);
}
Position Position::down() {
return Position(x + 1, y);
}
bool Position::overstep(bool map[][N]) {
return (x > N || x < 1 || y > N || y < 1); //若越界则返回true,否则返回false
}
bool Position::is_obstacle(bool map[][N]) {
return (map[x - 1][y - 1] == 1); //若迷宫该坐标为1,则表示为障碍,返回true
}
Stack::Stack() {
top = -1; //初始化栈为空
Position path_[maxsize];
}
bool Stack::isempty() {
return (top == -1); //栈为空返回true,否则返回false
}
void Stack::push(Position c) {
if (top == maxsize - 1) //上溢时扩大数组
throw "上溢";
top++;
path_[top].setpos(c.getx(), c.gety());
}
Position Stack::pop() {
if (isempty())
throw "栈为空";
return path_[top--];
}
Position Stack::gettop() {
if (isempty())
throw "栈为空";
return path_[top];
}
最后是简单的测试代码
测试代码因为嫌麻烦没有处理异常- -!
利用深度优先搜索解决简单的迷宫问题,其核心函数定义在下面。
/*
迷宫问题,入口和出口唯一,每次有四个方向移动,规定迷宫大小为10x10
*/
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
#include "stack.h"
bool map[N][N]; //用bool型二维数组表示10x10的地图
bool book[N][N]; //标记每个坐标是否走过,0表示没走过,1表示走过
Position des; //储存终点坐标
Stack path; //存储路径的栈
void next(Position now);
bool arrived();
int main() {
cout << "输入一个10x10的迷宫:障碍物输入1,空地输入0" << endl;
for (int i = 0; i < N; i++) { //输入迷宫
for (int j = 0; j < N; j++) {
cin >> map[i][j];
}
}
cout << "迷宫如下:" << endl;
cout << " 1 2 3 4 5 6 7 8 9 10" << endl; //输出列号
for (int i = 0; i < N; i++) {
if (i == 9)
cout << i + 1; //输出行号,第十行时为了对齐少打印一个空格
else
cout << i + 1 << " "; //输出行号
for (int j = 0; j < N; j++) { //输出第j+1行
cout << " "; //用于对齐
if (map[i][j] == 1)
cout << "*"; //障碍物打印'*'
else
cout << " "; //空地打印空格
}
cout << endl;
}
int x, y;
cout << "输入起点坐标(行,列)" << endl;
cin >> x >> y;
Position now(x, y); //当前坐标
cout << "输入终点坐标" << endl;
cin >> x >> y;
des.setpos(x, y); //输入终点坐标
next(now);
if (!arrived()) //遍历所有可能走不到终点
cout << "没有出口" << endl;
else {
Stack result; 因为栈不能从头输出,所以将path栈倒进result栈再输出即可实现逆序输出
while (!path.isempty())
result.push(path.pop()); //path出栈后入result栈
cout << "从起点到终点的路径为:" << endl;
int i = 0; //记录输出了几个坐标,使输出更加工整
while (!result.isempty()) {
i++;
result.pop().print();
cout << " ";
if (i % 5 == 0) //为了整齐,每5个坐标换一行
cout << endl;
}
}
return 0;
}
bool arrived() {
return (path.gettop().getx() == des.getx() && path.gettop().gety() == des.gety()); //到达终点返回true
}
void next(Position now) {
path.push(now); //当前坐标入栈
if (book[now.getx() - 1][now.gety() - 1] == 1) {
path.pop(); //若当前坐标已经走过,则出栈并返回上一层递归
return;
}
if (arrived())
return; //若已经到达终点,则返回上一层递归
if (now.is_obstacle(map) || now.overstep(map)) {
path.pop(); //若当前坐标是障碍或者越界,则出栈并返回上一层递归
return;
}
book[now.getx() - 1][now.gety() - 1] = 1; //设置当前坐标为走过
/*
用递归的方式寻找每一步可以走的路径,以右,上,下,左为顺序
*/
next(now.right()); //先一直向右走,直到到达终点或遇到障碍或越界
if (arrived())
return;
next(now.up()); //再退回来往上走,重复
if (arrived())
return;
next(now.down()); //往下走
if (arrived())
return;
next(now.left()); //往左走
if (arrived())
return;
book[now.getx() - 1][now.gety() - 1] = 0; //当前坐标四个方向都试过后设为未走过,供接下来的尝试继续使用
return;
}