前言
- 最近保持一周三更,出十篇数据结构的博客之后会出Java的。
- 博客排版会逐步规范。
- 代码排版会沿用我自己的风格并且继续改进。代码注释会反复考虑,如果过于复杂就会分块排版代码。
- 这篇博客之后会上一个栈的基本操作的文件和一篇随机生成迷宫的程序博客。
- 后续会在GitHub上面找项目一起看,虽然没几个人看🙃
最近看到一句区别栈和队列很形象的话:
栈是先进后出,队列是先进先出
所以吃多了吐就是栈,吃多了拉就是队列
问题概述
如上面的迷宫,用栈实现求迷宫路径的程序,所求路径不需要是最短路径,但必须是简单路径,即在求得的路径上不能重复出现同一通道块。比如当走到(1,8)时,发现无路可走了,则依次退栈,退到能走通的通道快,而不是往回走(即(2,8)再次入栈)。
程序思路
穷举求解
计算机求解迷宫问题的方法就是穷举求解,即从入口出发,顺某一方向向前探索,若能走通,则继续往前走;否则沿原路返回,换一个方向再继续探索,直至所有可能的通路都探索为止。为了保证在任何位置上都能沿原路退回,就需要用到一个先进先出的结构来保存从入口到当前位置的路径,那就是栈。
假设”当前位置“指的是”在搜索过程中某一时刻所在图中某个方块的位置“,则求解迷宫问题的基本思路就是:若”当前位置“可通”,则纳入”当前位置“(入栈),并继续朝”下一位置”探索,即切换“下一位置”为“当前位置”,如此重复直至到达出口;若“当前位置”不可通“,则应顺着“来向”退回到“前一通道快”(当前栈顶元素退栈后的栈顶元素),然后朝着除“来向”(前栈顶元素的方向)之外的其他方向继续探索;若该通道快的四周4个方块均“不可通”,则应从“当前路径”上删除该通道快(再次退栈)。
若以栈S记录“当前路径”,则栈顶中存放的是“当前路径上最后一个通道快”(当栈顶为出口时即求解完成),最后的求得的栈S从栈底到栈顶即是求得的路径,但是输出的路径用序号在迷宫图上表示。
代码实现
自定义一个迷宫
main函数里首先要创建一个自定义的迷宫。用一个二维数组来记录迷宫,把墙的值设为0,即不可通,把通道的值设为1,即可通。这里的程序把迷宫的四周都设定为墙,然后设定迷宫内部墙的位置,再指定迷宫的入口和出口。
int X, Y, i, j, n;
cout << "输入迷宫的行数,列数:" << endl;
cin >> X >> Y;
for (i = 0; i < Y; i++) // 定义上下边的墙值为0
{
m[0][i] = 0;
m[X - 1][i] = 0;
}
for (j = 1; j < X - 1; j++) //定义左右边除了第一行和最后一行的墙值为0(第一行和最后一行在上个循环中定义过)
{
m[j][0] = 0;
m[j][Y - 1] = 0;
}
for (i = 1; i < X - 1; i++) //定义所有内墙值为1(即通路)
for (j = 1; j < Y - 1; j++)
m[i][j] = 1;
cout << "请输入迷宫的内墙数:" << endl;
cin >> n;
for (i = 0; i < n; i++)
{
int x, y; //输入内墙的坐标值,以左上角坐标为(1,1)计算
cout << "输入第" << i + 1 << "个内墙的位置" << endl;
cin >> x >> y;
m[x][y] = 0;
}
数据的结构
typedef int MazeType[MAXLENGTH][MAXLENGTH]; // 迷宫数组[行][列]
MazeType m; //声明一个全局迷宫对象m
typedef int Status;
typedef struct //坐标
{
int x;
int y;
} PosType;
typedef struct
{
int ord; //通道块在路径上的“序号”
PosType seat; //通道块在迷宫中的“坐标位置”
int di; //从从此通道块走向下一通道块的“方向”
} SElemType; //栈的元素类型
typedef