数据结构-----迷宫问题

作者:黑衣侠客


前言

最近学习数据结构中,需要完成老师布置的作业,所以,研究了下迷宫问题,看起来很难的迷宫问题,其实,解决方法有很多,下面我将为大家介绍,用栈是如何解决迷宫问题的。

思路

首先,我们应该在代码中布置迷宫的地图,在布置迷宫地图时,以二维数组来存储每个点的数值,二维数组的好处是可以用坐标进行表示,此时,我设的是1为障碍物(墙),0为通路,下面来看一下,我在代码中所写的迷宫地图。
使用二维数组来对迷宫地图进行编辑
之后,我们定义一个栈结构,栈的每一层用来存储走过的每个格子的横坐标,纵坐标,以及从这个格子到下一格子所对应的方向的数字(在这里,我定义的方向是:0-上,1-右,2-下,3-左),然后再定义一个int型的指针,用于从栈底一次遍历到栈顶,方便对每一层的数据进行操作。具体代码是这样的:
typedef struct
{
    int i;              //当前方块的行号
    int j;              //当前方块的列号
    int di;             //di是下一可走相邻方位的方位号---上下左右的标记
} Box;
typedef struct
{
    Box data[MaxSize]; //是用来存储位置坐标的,当MaxSize<位置坐标的数目时,则程序出错,停止运行
    int top;            //栈顶指针
} StType;               //定义栈类型
然后我们再来说一下,具体的操作方法:
1.定义了mgpath方法,用来执行具体的走迷宫的思想操作
int mgpath(int xi,int yi,int xe,int ye)
其中,xi为原点的横坐标,yi为原点的纵坐标,xe为终点的横坐标,ye为终点的纵坐标。

2.初始化之前定义的栈,将栈的指针top赋值-1,然后top自增为0,就是栈的第一层,也就是栈底,存放横纵坐标,以及方位值,然后将点所在位置标为-1,以免走重。
 int i,j,k,di,find;
    StType st;                  //定义栈st
    st.top=-1;                  //初始化栈顶指针
    st.top++;                   //初始方块进栈
    st.data[st.top].i=xi;//栈底一号存入横坐标数值
    st.data[st.top].j=yi;//栈底一号存入纵坐标数值
    st.data[st.top].di=-1;//????????????????????????????????
    mg[xi][yi]=-1;
3.这是最重要的一步,当栈不是空的时候就一直循环,直到找到终点为止,每次循环开始时,find都为0,而di为0~3,因此,满足条件时,进入内层循环,在内层循环的第一行有一个di++,原因是:每次循环开始时,di的值都为-1,di自增后,就满足了对横纵坐标操作的条件了,我按照上右下左的顺序,改变此时所在的位置坐标,(详解:当di=0时,若走不通,那么就再次进入循环,进行自增,依次类推…),然后,当找到下一个位置为0时(通路),find=1,然后top向上走,在创建一行空间,让每个走过的0位置,都变为-1,此外,需要注意是弹栈操作,当碰到死胡同的时候,那么就需要进行弹栈了,返回到上一步,并将该位置的值从-1变回到0(在进行图像操作时需要用到这一点),(这里不用担心会再次重复走到这个死胡同的位置,因为di++,直接在上一基础方位自增,而不是重新开始,所以不必担心这一点),至此,迷宫思想已全部完成,接下来就该做一些优化了。
while (st.top>-1)           //栈不空时循环
    {
        i=st.data[st.top].i;
        j=st.data[st.top].j;
        di=st.data[st.top].di;  //取栈顶方块
        if (i==xe && j==ye)     //找到了出口,输出路径
        {
            printf("迷宫路径如下:\n");
            for (k=0; k<=st.top; k++)
            {
                printf("\t(%d,%d)",st.data[k].i,st.data[k].j);
                if ((k+1)%5==0) //每输出5个元素,就换行
                    printf("\n");
            }
            printf("\n");
            return 0;      //找到路径之后,将所有路径打印出来,然后,程序结束
        }
        find=0;
        while (di<4 && find==0)     //找下一个可走方块
        {
            di++;
            switch(di)
            {
            case 0://向上走
                i=st.data[st.top].i-1;
                j=st.data[st.top].j;
                break;
            case 1://向右走
                i=st.data[st.top].i;
                j=st.data[st.top].j+1;
                break;
            case 2://向下走
                i=st.data[st.top].i+1;
                j=st.data[st.top].j;
                break;
            case 3://向左走
                i=st.data[st.top].i;
    j=st.data[st.top].j-1;
                break;
            }
            if (mg[i][j]==0) find=1;    //mg[i][j]==0说明:该点可以走--------------(该点为此时所在点的下一预判点)
        }
        if (find==1)                    //找到了下一个可走方块
        {
            st.data[st.top].di=di;      //修改原栈顶元素的di值
            st.top++;                   //下一个可走方块进栈
            st.data[st.top].i=i;
            st.data[st.top].j=j;
            st.data[st.top].di=-1;  //再次初始化方向数值
            mg[i][j]=-1;                //避免重复走到该方块-----------------------//让每一个点都变成起点,因此,既满足递归的条件,也避免重复走到该位置
        }
        else                            //没有路径可走,则退栈-----------???????????为什么要退栈?不是刚刚只判断了一个方向吗?
        {
            mg[st.data[st.top].i][st.data[st.top].j]=0;//让该位置变为其他路径可走方块
            st.top--;                   //将该方块退栈
        }
4.我在主函数中,添加了一些优化操作,主要对输入原点以及图像做了简单处理。
 while(1){
   printf("请输入起点坐标:\n");
   printf("(横坐标范围:0~9,纵坐标范围:0~9)\n");
   scanf("%d %d",&x,&y);
   if(mg[x][y]==1){
   printf("输入坐标有误,该位置为墙,请重新输入:\n");
   }else{
    break;
   }
 }
图像处理:
 printf("\n\n图像表示:\n");
 for(t=0;t<10;t++){
  printf("\t\t");
  for(k=0;k<10;k++){
   if(mg[t][k]==1){
    printf("#");
   }else if(mg[t][k]==0){
    printf(" ");
   }else{
    printf("o");
   }
  }
  if(k==10){
   printf("\n");
  }
 }
 printf("\n此时,o所代表的图标为迷宫行走路径!!!\n");

代码部分

#include <stdio.h>
#define MaxSize 100
#define M 8
#define N 8
int mg[M+2][N+2]=
{
    {1,1,1,1,1,1,1,1,1,1},
    {1,0,0,1,0,0,0,1,0,1},
    {1,0,0,1,0,0,0,1,0,1},
    {1,0,0,0,0,1,1,0,0,1},
    {1,0,1,1,1,0,0,0,0,1},
    {1,0,0,0,1,0,0,0,0,1},
    {1,0,1,0,0,0,1,0,0,1},
    {1,0,1,1,1,0,1,1,0,1},
    {1,1,0,0,0,0,0,0,0,1},
    {1,1,1,1,1,1,1,1,1,1}
};//构造地图
typedef struct
{
    int i;              //当前方块的行号
    int j;              //当前方块的列号
    int di;             //di是下一可走相邻方位的方位号---上下左右的标记
} Box;
typedef struct
{
    Box data[MaxSize]; //是用来存储位置坐标的,当MaxSize<位置坐标的数目时,则程序出错,停止运行
    int top;            //栈顶指针
} StType;               //定义栈类型
//该栈中:每一个位置用于存储Box,该栈对应了一个int型的top作为指针,依次移动,方便对栈中每一个位置进行操作,而Box中,存储了该迷宫位置的横坐标,纵坐标,和从上一位置移动到该位置所对应的方向数值
int mgpath(int xi,int yi,int xe,int ye) //求解路径为:(xi,yi)->(xe,ye)
     //初位置横坐标,初位置纵坐标,终点横坐标,终点纵坐标
{
    int i,j,k,di,find;
    StType st;                  //定义栈st
    st.top=-1;                  //初始化栈顶指针
    st.top++;                   //初始方块进栈
    st.data[st.top].i=xi;//栈底一号存入横坐标数值
    st.data[st.top].j=yi;//栈底一号存入纵坐标数值
    st.data[st.top].di=-1;//????????????????????????????????
    mg[xi][yi]=-1;
    while (st.top>-1)           //栈不空时循环
    {
        i=st.data[st.top].i;
        j=st.data[st.top].j;
        di=st.data[st.top].di;  //取栈顶方块
        if (i==xe && j==ye)     //找到了出口,输出路径
        {
            printf("迷宫路径如下:\n");
            for (k=0; k<=st.top; k++)
            {
                printf("\t(%d,%d)",st.data[k].i,st.data[k].j);
                if ((k+1)%5==0) //每输出5个元素,就换行
                    printf("\n");
            }
            printf("\n");
            return 0;      //找到路径之后,将所有路径打印出来,然后,程序结束
        }
        find=0;
        while (di<4 && find==0)     //找下一个可走方块
        {
            di++;
            switch(di)
            {
            case 0://向上走
                i=st.data[st.top].i-1;
                j=st.data[st.top].j;
                break;
            case 1://向右走
                i=st.data[st.top].i;
                j=st.data[st.top].j+1;
                break;
            case 2://向下走
                i=st.data[st.top].i+1;
                j=st.data[st.top].j;
                break;
            case 3://向左走
                i=st.data[st.top].i;
    j=st.data[st.top].j-1;
                break;
            }
            if (mg[i][j]==0) find=1;    //mg[i][j]==0说明:该点可以走--------------(该点为此时所在点的下一预判点)
        }
        if (find==1)                    //找到了下一个可走方块
        {
            st.data[st.top].di=di;      //修改原栈顶元素的di值
            st.top++;                   //下一个可走方块进栈
            st.data[st.top].i=i;
            st.data[st.top].j=j;
            st.data[st.top].di=-1;  //再次初始化方向数值
            mg[i][j]=-1;                //避免重复走到该方块-----------------------//让每一个点都变成起点,因此,既满足递归的条件,也避免重复走到该位置
        }
        else                            //没有路径可走,则退栈-----------???????????为什么要退栈?不是刚刚只判断了一个方向吗?
        {
            mg[st.data[st.top].i][st.data[st.top].j]=0;//让该位置变为其他路径可走方块
            st.top--;                   //将该方块退栈
        }
    }
    return(0);                          //表示没有可走路径,返回0
}
int main()
{
 int x,y,k,t;
 printf("终点坐标为:(8,8)\n");
 while(1){
   printf("请输入起点坐标:\n");
   printf("(横坐标范围:0~9,纵坐标范围:0~9)\n");
   scanf("%d %d",&x,&y);
   if(mg[x][y]==1){
   printf("输入坐标有误,该位置为墙,请重新输入:\n");
   }else{
    break;
   }
 }
  mgpath(x,y,M,N);
 printf("\n\n图像表示:\n");
 for(t=0;t<10;t++){
  printf("\t\t");
  for(k=0;k<10;k++){
   if(mg[t][k]==1){
    printf("#");
   }else if(mg[t][k]==0){
    printf(" ");
   }else{
    printf("o");
   }
  }
  if(k==10){
   printf("\n");
  }
 }
 printf("\n此时,o所代表的图标为迷宫行走路径!!!\n");
    return 0;
}

运行结果

在这里插入图片描述

以上全部代码由vc++6.0调试成功
本次代码,我已传到github上------迷宫问题
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐