版权声明:转用请注明出处 https://blog.csdn.net/weixin_39411321/article/details/89283574
问题描述:
利用OOP思想完成迷宫路径的寻找问题
程序运行要求如下:
请输入迷宫的行列数: 5 5
请输入迷宫路径节点信息(1表示不能走,0表示能走)
开始寻找迷宫路径(从左上角到右下角的一个可通行的路径):
迷宫存在可通行的路径:
程序所包含的头文件和如下
#include "targetver.h"
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<stdio.h>
#include<fstream>
#include <tchar.h>
using namespace std;
const int RIGHT = 0;
const int DOWN = 1;
const int LEFT = 2;
const int UP = 3;
const int OK = 4;
const int ERR = 5;
题目分析:
先抽象出来三个类:
迷宫结点类(MazeNode )
结点类的成员变量:
结点的坐标:mx,my;
结点的值:mval(0/1);
结点的四个方向(up/down/right/left);
class MazeNode
{
public:
MazeNode()
{
// 先初始化迷宫路径的四个方向为可行走状态
for (int i = 0; i < 4; ++i)
{
mway[i] = OK; //初始化把结点的四个方向都设置为可状态
}
}
int getVal() { return mval; }
int getX() { return mx; }
int getY() { return my; }
int getWayState(int way) { return mway[way]; }
void setWayState(int way, int state) { mway[way] = state; }//设置方向状态
void setVal(int val) { mval = val; }
void setX(int x) { mx = x; }
void setY(int y) { my = y; }
private:
int mval;
int mx;
int my;
int mway[4];
};
迷宫类(Maze)
迷宫类的成员变量:
迷宫的行mrow和列mcol;
迷宫的结点MazeNode **mpcells;
存放迷宫路径的Stack mstack;
迷宫类的成员方法:
// 调整路径的行走状态信息
setMazeNodeState();
//设置结点信息
setMazeNode(int val, int i, int j)
// 开始寻找迷宫路径
findMazePath();
// 打印迷宫路径信息
showResult();
迷宫类的代码如下:
class Maze
{
public:
Maze(int r, int c)
:mrow(r), mcol(c) //动态开辟了一个二维数组存放迷宫结点
{
mpcells = new MazeNode*[mrow]; //先开辟一维数组
for (int i = 0; i < mrow; ++i)
{
mpcells[i] = new MazeNode[mcol]; //在一维的基础上再开辟二维
}
}
~Maze()
{
for (int i = 0; i < mrow; ++i)
{
delete[]mpcells[i];
}
delete[]mpcells;
mpcells = nullptr;
}
void setMazeNode(int val, int i, int j)
{
mpcells[i][j].setVal(val);
mpcells[i][j].setX(i);
mpcells[i][j].setY(j);
}
void setMazeNodeState()
{
for (int i = 0; i < mrow; ++i)
{
for (int j = 0; j < mcol; ++j)
{
if (mpcells[i][j].getVal() == 1)//如果值为1 说明不可走
{
continue;
}
if (i == 0)//说明是第一行则把他的上方向置为不可走
{
mpcells[i][j].setWayState(UP, ERR);
}
if (j == 0)//说明是第一列则把他的左方向置为不可走
{
mpcells[i][j].setWayState(LEFT, ERR);
}
if (i == mrow - 1)//说明是最后一行则把他的下方向置为不可走
{
mpcells[i][j].setWayState(DOWN, ERR);
}
if (j == mcol - 1)//说明是最后一列则把他的右方向置为不可走
{
mpcells[i][j].setWayState(RIGHT, ERR);
}
if (i>0 && mpcells[i - 1][j].getVal() == 1)
//不是第一行且他的上方向[i - 1][j]的值为1,则把他的上方向置为不可走;
{
mpcells[i][j].setWayState(UP, ERR);
}
if (i<mrow - 1 && mpcells[i + 1][j].getVal() == 1)
//不是最后一行且他的下方向[i + 1][j]的值为1,则把他的下方向置为不可走;
{
mpcells[i][j].setWayState(DOWN, ERR);
}
if (j>0 && mpcells[i][j - 1].getVal() == 1)
//不是第一列且他的左方向[i][j - 1]的值为1,则把他的左方向置为不可走;
{
mpcells[i][j].setWayState(LEFT, ERR);
}
if (j<mcol - 1 && mpcells[i][j + 1].getVal() == 1)
//不是最后一列且他的右方向[i][j + 1]的值为1,则把他的右方向置为不可走;
{
mpcells[i][j].setWayState(RIGHT, ERR);
}
}
}
}
void findMazePath()
{
//若迷宫的起始结点的值为1,则肯定不存在迷宫路径;
if (mpcells[0][0].getVal() == 1)
return;
//把正确的路径结点压入stack中;
mstack.push(mpcells[0][0]);
while (!mstack.empty())
{
MazeNode top = mstack.top();
int x = top.getX();
int y = top.getY();
if (x == mrow - 1 && y == mcol - 1)//如果到达了迷宫的右下角则退出;
{
return;
}
//我们自己默认了一个结点的查询方向依次为右下左上
//如果某一个结点的右边的的状态为可走
if (mpcells[x][y].getWayState(RIGHT) == OK)
{
mpcells[x][y].setWayState(RIGHT, ERR);
//把当前结点的右方向置为不可走 表示已经走过这条路径以后不能再走这条冤枉路了
//以防止后来出栈后继续走这条路导致在这里死循环
//详细下边会讲
mpcells[x][y + 1].setWayState(LEFT, ERR);
//同理把右边结点的左方向也置为不可走
mstack.push(mpcells[x][y + 1]);
//然后把右边的结点进行压栈 压入到迷宫的正确路径里边去
continue;
}
//以下三个方向的调整思想都是同理的
if (mpcells[x][y].getWayState(DOWN) == OK)
{
mpcells[x][y].setWayState(DOWN, ERR);
mpcells[x + 1][y].setWayState(UP, ERR);
mstack.push(mpcells[x + 1][y]);
continue;
}
if (mpcells[x][y].getWayState(LEFT) == OK)
{
mpcells[x][y].setWayState(LEFT, ERR);
mpcells[x][y - 1].setWayState(RIGHT, ERR);
mstack.push(mpcells[x][y - 1]);
continue;
}
if (mpcells[x][y].getWayState(UP) == OK)
{
mpcells[x][y].setWayState(UP, ERR);
mpcells[x - 1][y].setWayState(DOWN, ERR);
mstack.push(mpcells[x - 1][y]);
continue;
}
//走到这一步说明该结点的四个方向都是不可走的
//所以我们要出栈试一试上个结点的其他方向是否可以通
//这时候回到上个结点就不能走这个结点的方向了
//而要走默认顺序的四个方向的下一个方向
//因为我们当时已经把要走的下一个方向的状态置为不可走了
//如果上个结点的四个方向也不通则一直出栈
//直到栈空 说明没有正确的通的迷宫路径
mstack.pop();
}
}
void showResult()
{
if (mstack.empty())//判断路径栈是否空
{
cout << "该迷宫不存在可通行的路径" << endl;
return;
}
cout << "该迷宫存在可通行的路径为:" << endl;
while (!mstack.empty())//把栈里边的正确路径信息的结点的值都设置为*;
{
MazeNode node = mstack.top();
mpcells[node.getX()][node.getY()].setVal('*');
mstack.pop();
}
//打印出迷宫
for (int i = 0; i < mrow; ++i)
{
for (int j = 0; j < mcol; ++j)
{
if (mpcells[i][j].getVal() == '*')
{
cout << "*" << " ";
}
else
{
cout << mpcells[i][j].getVal() << " ";
}
}
cout << endl;
}
}
private:
int mcol;
int mrow;
MazeNode **mpcells;
Stack mstack;
};
存放迷宫正确通路径的stack类(Stack)
栈就不用多说了;就是很简单的出栈和入栈操作
代码如下:
class Stack
{
public:
// 成员方法,操作的就是成员变量
Stack(int size = 10)
:mtop(-1), msize(size)
{
mpStack = new MazeNode[msize];
}
~Stack()
{
delete[]mpStack;
mpStack = nullptr;
}
void push(MazeNode &p)
{
if (this->full())
this->resize();
mpStack[++mtop] = p;
}
void pop()
{
if (this->empty())
return;
this->mtop--;
}
MazeNode top()const
{
if (empty())
throw"";
return this->mpStack[this->mtop];
}
bool full()const { return this->mtop == this->msize - 1; }
bool empty()const { return this->mtop == -1; }
private:
MazeNode *mpStack; // 存放栈的元素
int mtop; // 栈顶指针
int msize; // 栈的总长度
void resize()//stack的动态扩容函数要私有化
{
MazeNode* ptemp = new MazeNode[msize * 2];
for (int i = mtop; i >= 0; i--)
{
ptemp[i] = mpStack[i];
}
delete[]mpStack;
mpStack = ptemp;
msize *= 2;
}
};
主函数:
int main()
{
cout << "输入迷宫的大小:";
int row, col;
cin >> row >> col;
Maze maze(row, col);
cout << "输入迷宫路径信息:" << endl;
for (int i = 0; i < row; ++i)
{
for (int j = 0; j < col; ++j)
{
int data;
cin >> data; // data [i, j]
maze.setMazeNode(data, i, j);
}
}
// 调整路径的行走状态信息
maze.setMazeNodeState();
// 开始寻找迷宫路径
maze.findMazePath();
// 打印迷宫路径信息
maze.showResult();
return 0;
}