利用栈结构进行回退从而解决迷宫寻路问题
寻得的路径仅仅是一条可到达目的地的路径
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
//数组里面去寻路:位置--->行列
struct position
{
int row;
int cols;
};
struct position pathStack[100]; //栈内存(存放路径)
int stackTop = -1; //栈顶标记
int** maze = NULL; //二维数组去描述地图
int size = 0; //迷宫的大小
int** makeArray(int row, int cols) //二级指针指向二维数组
{
int** array = (int**)malloc(sizeof(int*) * row);
for (int i = 0; i < cols; i++)
{
array[i] = (int*)malloc(sizeof(int) * cols);
}
return array;
}
//用户输入一个迷宫
void createMaze()
{
printf("输入迷宫大小:");
scanf("%d", &size);
maze = makeArray(size + 2, size + 2);//加2表示边框
printf("输入迷宫:\n");
for (int i = 1; i <= size; i++)
{
for (int j = 1; j <= size; j++)
{
scanf("%d", &maze[i][j]);
}
}
//加边框 1表示墙,不可以走
for (int i = 0; i <= size + 1; i++)
{
//第一行和第size+2行
maze[0][i] = 1;
maze[size + 1][i] = 1;
//第一列和第size+2列
maze[i][0] = 1;
maze[i][size + 1] = 1;
}
}
//寻找路径
int findPath()
{
//偏移量描述出来
struct position offset[4]; //0-3表示4个不同的方向
//偏移量=>方向
//往右边走
offset[0].row = 0;
offset[0].cols = 1;
//往下边走
offset[1].row = 1;
offset[1].cols = 0;
//往左边走
offset[2].row = 0;
offset[2].cols = -1;
//往上边走
offset[3].row = -1;
offset[3].cols = 0;
//等效 => struct position offset[4] = { {0,1},{1,0},{0,-1},{-1,0} };
//选定入口
struct position here = { 1,1 };//当前的位置坐标
//走迷宫=>记录走过的路径
//走过的地方标记为1
maze[1][1] = 1;
int option = 0; //下一个移动方向
int endOption = 3; //终止方向
while (here.row != size || here.cols != size)//终点位置为(size,size)
{
//未到达终点位置时,继续走
int rowNum, colsNum; //记录下标变化
while (option <= endOption)
{
//行列变化 = 原位置 + 偏移值 (偏移值由方向决定)
rowNum = here.row + offset[option].row;
colsNum = here.cols + offset[option].cols;
//一旦确定一个方向可以走,就需要去下一步
if (maze[rowNum][colsNum]==0)
{
break; //能走,退出循环,走到下一个位置
}
else//不能走,换方向测试
{
option++;
}
}
//跳出上面while可能是有break跳出的(这时option<=endOption) 这种情况下有路可以走
//也可以是由于option > endOption不再满足while循环条件造成的 这种情况下无路可走
if (option <= endOption)//有路可以走
{
//走到下一个
pathStack[++stackTop] = here;
//改变当前位置
here.row = rowNum;
here.cols = colsNum;
//走过的路径标记=>堵上
maze[rowNum][colsNum] = 1;
option = 0; //起始方向置为零去找下一个位置
}
else//这时option > endOption(option等于4),无路可走,接下来要进行退步(回到上一步去)
{
//回到上一步去
if (stackTop == -1) return 0;//栈为空,无路可走(没有路径)
struct position next = pathStack[stackTop--];//出栈方式=>回退到上一步
//方向的处理
if (next.row == here.row)//行不变,左右走
{
option = (2 + next.cols - here.cols) % 4;
}
else//行发生变化,则列不变。上下变化。
{
option = (3 + next.row - here.row) % 4;
}
here = next; //位置回退到上一个位置
}
}
return 1;
}
//打印路径
void printPath()
{
if (stackTop == -1)
{
printf("无路可走\n");
}
else
{
printf("路径方式:\n");
struct position curPos;
while (stackTop != -1)
{
curPos = pathStack[stackTop--];
printf("(%d,%d)-->", curPos.row, curPos.cols);
}
printf("\n");
}
}
int main()
{
createMaze();
if (findPath()) printPath();
else printf("无路可走!\n");
return 0;
}
思路:从起点开始,按着右、下、左、上的方向(偏移量)进行寻路。只要偏移后的位置的数值为零就过去。每到达一个位置,就将该位置入栈,并将该位置的二维数组的值设为1来标记已经走过。若一个点的四周都无路可走,则进行回退出栈。
核心:findPath();函数
方向的处理:
这里方向的处理不太容易理解:
当一个位置的四个方向都无路可走时(即该位置的四个方向都被标记为1),就需要进行回退出栈。
首先是位置的回退:将其回退到该位置的前一个位置。
其次是方向的回退:这时我们如果将方向option置为0并不会影响寻路的结果,但是会减小寻路的效率。
当我们将回退后的位置改为到达无路可走位置的方向的下一个方向时。效率更高,因为避免尝试了不可能通过的方向。
如下:
-
当行不变时说明是左右移动的,由左往右移动时,next.cols - here.cols=-1,回退后的方向应该是向下为1;由右往左移动时,next.cols - here.cols=1,回退后的方向应该为3。综上考虑,回退后的方向应该为:option = (2 + next.cols - here.cols) % 4;
-
行改变时,列就不发生变化。这时应该为上下移动。由下往上移动时,next.row - here.row=1,回退后的方向应该为0;由上向下移动时,next.row - here.row=-1,回退后的方向应该为2。综上所述,回退后的方向应该为:option = (3 + next.row - here.row) % 4;