介绍
迷宫问题一般深度优先遍历或者广度优先遍历解决,辅助数据结构使用栈或者队列。使用栈解决该问题时,将栈顶能达到的一个位置入栈,若发现该路不通,则退栈,通过栈顶元素继续访问其他可达到的位置,直到走完整个迷宫。若使用非循环队列,将队头能到达的所有位置入队,并记录该位置的前驱为队头元素,最后通过队列的元素的前驱记录可得到整个迷宫的路线。
问题描述
有一个迷宫地图,有一些可达的位置,也有一些不可达的位置(障碍、墙壁、边界)。从一个位置到下一个位置只能通过向上(或者向右、或者向下、或者向左)走一步来实现,从起点出发,如何找到一条到达终点的通路。本文将用两种不同的解决思路,四种具体实现来求解迷宫问题。
用二维矩阵来模拟迷宫地图,1代表该位置不可达,0代表该位置可达。每走过一个位置就将地图的对应位置标记,以免重复。找到通路后打印每一步的坐标,最终到达终点位置。
使用不循环队列
原理描述
先第一个位置入队,将队头能到达的所有位置入队,并记录该位置的前驱为队头元素,最后通过队列的元素的前驱记录可得到整个迷宫的路线。
算法描述
#include <stdio.h>
#define Maxsize 100
#define N 4
int M[N + 2][N + 2] =
{
{ 1,1,1,1,1,1},
{ 1,0,1,1,1,1},
{ 1,0,1,0,1,1},
{ 1,0,0,0,1,1},
{ 1,1,0,0,0,1},
{ 1,1,1,1,1,1},
};
struct path
{
int i, j, p;
}Q[Maxsize];
int front = -1;
int rear = -1;
void print(int front)
{
int k = front, i = 0, j;
while (k != 0)
{
j = k;
k = Q[k].p;
Q[j].p = -1;
}
printf("迷宫最快捷路径如下:\n");
k = 0;
while (k<Maxsize)
{
if (Q[k].p == -1)
{
i++;
printf("(%d,%d)\t", Q[k].i, Q[k].j);
M[Q[k].i][Q[k].j] = 0;
printf("\n");
}
k++;
}
printf("\n迷宫最快捷路径如图所示:\n");
for (i = 0; i<N + 2; i++)
{
for (j = 0; j<N + 2; j++)
{
printf("%3d", M[i][j]);
}
printf("\n");
}
}
int labyrinth(int x1, int y1, int x2, int y2)
{
int i, j, find = 0, di;
rear++;
Q[rear].i = x1; Q[rear].j = y1; Q[rear].p = -1;
M[1][1] = -1;
while (front <= rear && find == 0)
{
front++;
i = Q[front].i; j = Q[front].j;
if (i == x2 && j == y2)
{
find = 1;
print(front);
return 1;
}
for (di = 0; di<4; di++)
{
switch (di)
{
case 0:
i = Q[front].i - 1; j = Q[front].j; break;
case 1:
i = Q[front].i; j = Q[front].j + 1; break;
case 2:
i = Q[front].i + 1; j = Q[front].j; break;
case 3:
i = Q[front].i; j = Q[front].j - 1; break;
}
if (M[i][j] == 0)
{
rear++;
Q[rear].i = i; Q[rear].j = j; Q[rear].p = front;
M[i][j] = -1;
}
}
}
return 0;
}
void main()
{
labyrinth(1, 1, N, N);
getchar();
}
运行结果
使用栈
使用栈的思路较为简单,将栈顶能达到的一个位置入栈,若发现该路不通,则退栈,通过栈顶元素继续访问其他可达到的位置,直到走完整个迷宫。
迷宫数据
本文算法将迷宫数据存放于一个文件中,从文件中读取迷宫矩阵,最后使用栈解决迷宫问题。
{ 1,1,1,1,1,1},
{ 1,0,1,1,1,1},
{ 1,0,1,0,1,1},
{ 1,0,0,0,1,1},
{ 1,1,0,0,0,1},
{ 1,1,1,1,1,1},
算法描述
#include <stdio.h>
#include <stdlib.h>
#define maxsize 20
typedef struct Matrix{
int data[maxsize][maxsize];
int rowNum;
int colNum;
}Matrix;
typedef struct Elem{
int i; //横坐标
int j; //纵坐标
}Elem;
//从文本中读入数据
int readMatrix(Matrix * matrix,const char * path){
FILE * fp;
int i,j;
char c;
if((fp = fopen(path,"r")) == NULL){
printf("文件打开失败\n");
return 0;
}
i = 0;
j = 0;
while((c = fgetc(fp)) != EOF){ //读取一个字符
if(c == '\n'){ //若读取到换行符则从矩阵的下一行开始赋值
j = 0;
i++;
continue;
}
if(c == ' '){ //不读取空格
continue;
}
matrix->data[i][j] = c - 48; //将字符转换为数字
j++;
}
matrix->rowNum = i + 1;
matrix->colNum = j;
if(fp != NULL){
fclose(fp);
fp = NULL;
}
return 1;
}
//显示迷宫
void showMatrix(Matrix * matrix){
int i,j;
for(i = 0; i<matrix->rowNum; i++){
for(j = 0; j < matrix->colNum; j++){
printf("%3d",matrix->data[i][j]);
}
printf("\n");
}
}
//寻找迷宫路劲
int computePath(Matrix * matrix,int x1,int y1,int x2,int y2){
Elem stack[maxsize * maxsize];
int top;
int i,j,k,find,dir,_i,_j;
top = -1;
//先将迷宫中的入口加入到栈中
top ++;
stack[top].i = x1;
stack[top].j = y1;
matrix->data[x1][y1]=-1;
while(top > -1){
i=stack[top].i;//取栈顶元素
j=stack[top].j;
matrix->data[i][j] = -1;
if(i==x2&&j==y2) {
printf("找到迷宫路劲:\n");
for(k=0; k<=top; k++) {
printf("(%d,%d)\n",stack[k].i,stack[k].j);
_i = stack[k].i;
_j = stack[k].j;
matrix->data[_i][_j] = 2;
}
printf("\n");
return 1;
}
find = 0;
dir = 0;
while(dir<4&&find==0) { //遍历当前位置的4个方向
switch(dir) {
case 0:
i=stack[top].i-1;//向上
j=stack[top].j;
break;
case 1:
i=stack[top].i; //向右
j=stack[top].j+1;
break;
case 2:
i=stack[top].i+1;//向下
j=stack[top].j;
break;
case 3:
i=stack[top].i;
j=stack[top].j-1;//向左
break;
}
if(matrix->data[i][j]==0) {
find=1;
break;
}
dir ++;
}
if(find==1) { //如果发现有路劲,则讲路劲坐标入栈
top++;
stack[top].i=i;
stack[top].j=j;
matrix->data[i][j]=-1;
} else { //否则将走不通,往回走,退栈
matrix->data[stack[top].i][stack[top].j]=-1;
top--;
if(top < 0){
showMatrix(matrix);
return 0;
}
}
}
}
int main(){
int flag;
Matrix matrix;
readMatrix(&matrix,"d:/1.txt");
printf("读取到迷宫数据:\n");
showMatrix(&matrix);
printf("\n");
flag = computePath(&matrix,1,1,matrix.rowNum-2,matrix.colNum-2);
printf("\n");
if(!flag){
printf("未找到迷宫路劲:\n");
return 0;
}
printf("打印路线图迷宫数据(2为所走路线):\n");
showMatrix(&matrix);
return 0;
}
总结
本文提供了两种解决迷宫问题的思路,其一为使用广度优先遍历(使用队列)解决,其二为使用深度优先遍历(使用栈)来解决,本文主要描述了广度优先遍历迷宫的思路,提供了算法描述和实验结果,另外也提供了栈的算法描述和实验数据。