好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

数据结构与算法大作业:走迷宫程序(C语言,DFS)(代码以及思路)

数据结构与算法大作业:走迷宫程序(C语言,DFS)(代码以及思路)

好家伙,写大作业,本篇为代码的思路讲解

 

1.大作业要求

走迷宫程序

问题描述:

以一个 m * n 的长方阵表示迷宫, 0和1分别表示迷宫的通路和障碍。 设计一个程序, 对任意设定的迷宫, 求出一条从入口到出口的通路, 或得出没有通路的结论。

基本要求:

(1) 实现一个以链表做存储的栈类型, 然后编写一个求解迷宫的非递归程序。 求的通路以三元组(i, j, d) 的形式输出, 其中:(i, j) 指示迷宫中的一个坐标, d 表示走到下一坐标的方向。 如: 对于下列数据的迷宫, 输出一条通路:

(1, 1, 1),(1, 2, 2),
(2, 2, 2),(3, 2, 3),(3, 1, 2) ……。

(2) 编写递归形式的算法, 求得迷宫中所有可能的道路;

扩展功能要求:

以方阵形式输出迷宫及其到道路

测试数据: 迷宫的测试数据如下: 左上角(1, 1) 为入口, 右下角(8, 9) 为出口。

 

作业要求

1、 选题:从4个题目中任选其一,独立完成。程序至少采用所学过的一种数据结构(链表、栈、队列、树等)实现。学生可以根据自己的需求分析适当地调整程序的合理性,使得程序能够更加贴近实际。每个题目选题人员不得超过15人,向学委报名选题情况,先报先得,每个题目满15人后必须另选其他题目。

2、 程序代码要求:程序要求能够正常运行,基本功能必须全部实现。完成可选做的扩展功能将得到较高的分数。容错性强和功能细节考虑更完全也将得到较高的分数。

3、 开发语言:软件工程和数据科学与大数据技术专业用Java语言,计算机科学与技术专业用C或C++语言。

 

2.分析

来概括一下

这是个迷宫程序,手动输入迷宫,找出所有解,输出所有解

数据结构要用栈

解法:

我们用一个二维度数组保存这个"迷宫"

1.随后,我们确定起点和终点,

2.先站在起点上,将起点入栈

3.我们开始寻路,按照东南西北(即右下左上)的方向顺序寻找下一坐标

3.1.如果该方向上有路,将下一坐标入栈,"走到"这个坐标上

3.2.如果下一坐标上是墙,则返回

3.3.如果下一个点是出口,则打印线路

 

3.单路径版本

大概是这样了

代码如下:

单路径版本

  #include <stdio.h> 
#include  <stdlib.h> 
#include  < string .h> 
 #define  MAXN 20
 struct  mark  //   定义迷宫内点的坐标类型 
 {
      int   x;
      int   y;
};
  struct  Element  //   链栈元素结点 
 {
      int  x, y;  //   x行,y列 
     int  d;       //   d下一步的方向 
 };

typedef   struct  LStack  //   链栈 
 {
    Element elem;
      struct  LStack *next;  //   指针变量 
 };

typedef LStack  * PLStack;

  /*  ……………………………栈函数……………………………  */ 
 int  InitStack(PLStack &S)  //   构造空栈 
 {
    S  =  NULL;
      return   1  ;
}
  int  StackEmpty(PLStack S)  //   判断栈是否为空 
 {
      if  (S ==  NULL)
          return   1  ;
      else 
         return   0  ;
}
  int  Push(PLStack &S, Element e)  //   压入新数据元素 
 {
    PLStack p;
    p  = (PLStack) malloc ( sizeof  (LStack));
    p ->elem =  e;
    p ->next =  S;
    S  =  p;
      return   1  ;
}
  int  Pop(PLStack &S, Element &e)  //   栈顶元素出栈 
 {
    PLStack p;
      if  (! StackEmpty(S))
    {
        e  = S-> elem;
        p  =  S;
        S  = S-> next;
          free  (p);
          return   1  ;
    }
      else 
         return   0  ;
}
  /*  ……………………求迷宫路径函数……………………………  */ 
 void  MazePath( struct  mark start,  struct  mark end,  int  maze[MAXN][MAXN],  int  diradd[ 4 ][ 2  ])
{
      int   i, j, d;
      int   a, b;
    Element elem, e;
    PLStack S1, S2;
    InitStack(S1);
    InitStack(S2);
    maze[start.x][start.y]  =  2 ;  //   入口点作上标记 
    elem.x =  start.x;
    elem.y  =  start.y;
    elem.d  = - 1 ;  //   开始为-1 
     Push(S1, elem);
      while  (!StackEmpty(S1))  //   栈不为空 有路径可走 
     {
        Pop(S1, elem);
        i  =  elem.x;
        j  =  elem.y;
        d  = elem.d +  1 ;  //   下一个方向 
         while  (d <  4 )     //   试探东南西北各个方向 
         {
            a  = i + diradd[d][ 0  ];
            b  = j + diradd[d][ 1  ];
              if  (a == end.x && b == end.y && maze[a][b] ==  0 )  //   如果到了出口 
             {
                elem.x  =  a;
                elem.y  =  b;
                elem.d  =  886 ;  //   方向输出为-1 判断是否到了出口 
                 Push(S1, elem);
                printf(  "  \n0=东 1=南 2=西 3=北 886为则走出迷宫\n\n通路为:(行坐标,列坐标,方向)\n  "  );
                  while  (S1)  //   逆置序列 并输出迷宫路径序列 
                 {
                    Pop(S1, e);
                    Push(S2, e);
                }
                  while   (S2)
                {
                    Pop(S2, e);
                    printf(  "  -->(%d,%d,%d)  "  , e.x, e.y, e.d);
                }
                  return ;  //   跳出两层循环,本来用break,但发现出错,exit又会结束程序,选用return 
             }
              if  (maze[a][b] ==  0 )  //   找到可以前进的非出口的点 
             {
                maze[a][b]  =  2 ;  //   标记走过此点 
                elem.x =  i;
                elem.y  =  j;
                elem.d  =  d;
                Push(S1, elem);   //   当前位置入栈 
                i = a;             //   下一点转化为当前点 
                j =  b;
                d  = - 1  ;
            }
            d ++ ;
        }
    }
    printf(  "  没有找到可以走出此迷宫的路径\n  "  );
}
  /*  ……………………………建立迷宫……………………………  */ 
 void  initmaze( int   maze[MAXN][MAXN])
{
      int   i, j;
      int  m, n;                        //   迷宫行,列 
    printf( "  请输入迷宫的行数 m=  " );  //   输入迷宫 
    scanf( "  %d  " , & m);
    printf(  "  请输入迷宫的列数 n=  "  );
    scanf(  "  %d  " , & n);
    printf(  "  \n请输入迷宫的各行各列:\n用空格隔开,0代表路,1代表墙\n  "  , m, n);
      for  (i =  1 ; i <= m; i++ )
    {
          for  (j =  1 ; j <= n; j++ )
            scanf(  "  %d  " , & maze[i][j]);
    }
    printf(  "  你建立的迷宫为\n  "  );
      for  (i =  0 ; i <= m +  1 ; i++)  //   加一圈围墙 
     {
        maze[i][  0 ] =  1  ;
        maze[i][n  +  1 ] =  1  ;
    }
      for  (j =  1 ; j <= n; j++ )
    {
        maze[  0 ][j] =  1  ;
        maze[m  +  1 ][j] =  1  ;
    }
      for  (i =  0 ; i <= m +  1 ; i++)  //   输出迷宫 
     {
          for  (j =  0 ; j <= n +  1 ; j++ )
            printf(  "  %d   "  , maze[i][j]);
        printf(  "  \n  "  );
    }
}

  int   main()
{
      int   sto[MAXN][MAXN];
      struct  mark start, end;                                 //   start,end入口和出口的坐标 
     int  add[ 4 ][ 2 ] = {{ 0 ,  1 }, { 1 ,  0 }, { 0 , - 1 }, {- 1 ,  0 }};  //   行增量和列增量 方向依次为东西南北 
    initmaze(sto);                                         //   建立迷宫 
    printf( "  输入入口的横坐标,纵坐标[空格隔开]\n  "  );
    scanf(  "  %d %d  " , &start.x, & start.y);
    printf(  "  输入出口的横坐标,纵坐标[空格隔开]\n  "  );
    scanf(  "  %d %d  " , &end.x, & end.y);
    MazePath(start, end, sto, add);   //   find path 
    printf( "  \n  "  );
}   

 

效果如下:

 

看上去没什么问题了,

 

但是,这种方法无法实现多条路径的打印

所以还是要使用搜索算法

下面,我们使用深度优先搜索来解决这个问题

此处我们使用递归的思想

 

4.最终版本

解法由:

用一个二维度数组保存这个"迷宫"

1.随后,我们确定起点和终点,

2.先站在起点上,将起点入栈

3.我们开始寻路,按照东南西北(即右下左上)的方向顺序寻找下一坐标

  3.1.如果该方向上有路,将下一坐标入栈,"走到"这个坐标上

  3.2.如果下一坐标是墙,则进行下一次循环

  3.3.如果下一个点是出口,则打印线路

 

改为

用一个二维度数组保存这个"迷宫"

1.随后,我们确定起点和终点,

2.先站在起点上,将起点入栈

3.寻路方法(){

  "走到下一点上"(第一次调用时不做这步)

  3.1.开始寻路,按照东南西北(即右下左上)的方向顺序确定下一坐标,

  |  3.1.1如果该方向上有路,下一坐标入栈,并标记为2(标记为走过)

  |  |  3.1.1.1如果下一个点是出口,则打印线路,将下一坐标标记为0,栈顶出栈

  |  |  3.1.1.2.调用寻路方法

  |   3.1.2.开始下一次循环,回到3.1

  3.2.出栈,当前点赋值为0

}

 

核心算法部分实现:

   //  -----------遍历迷宫寻找路径(dfs)------------ 
 void  mazePath( int  x, int  y, int  endx, int  endy, int  n, int   m,Stack s){
      int   newx,newy,i;
    Node t;
      for (i= 0 ;i< 4 ;i++ ){
        newx =x+direction[i][ 0  ];
        newy =y+direction[i][ 1  ];
          if (newx>= 0 &&newx<n&&newy>= 0 &&newy<m&&maze[newx][newy]== 0 ){     //  下一个路能走  
             push(newx,newy,s);
            maze[newx][newy] = 2  ;
              if (newx==endx&&newy==endy){ //  走到出口  
                flag++ ;
                printPath(s,n,m);
                maze[newx][newy] = 0  ;
                pop(s);
            }
              else  {
                mazePath(newx,newy,endx,endy,n,m,s);   //  开始递归  
             }
        }
    }
    maze[x][y] = 0 ;    //  遍历完四个方向之后回溯前将自己赋为空 
     pop(s);
}   

 

完整代码:

所有路径版本:

  #include <stdio.h> 
#include  <stdlib.h> 
#include  < string .h>  
 #define  MAXN 20
 
 /*    *建立一个二维数组存迷宫
    *要是四个方向能有位置则压入栈,要是下一步没有则弹出栈回溯
    *直到找到终点为止
  */ 
 int  direction[ 4 ][ 2 ] = {{ 0 ,  1 }, { 1 ,  0 }, { 0 , - 1 }, {- 1 ,  0 }};   //  定义一个数组存四个方向操作数 
 int  MIN= 100 ; //  用于记录最小路径  
 int   maze[MAXN][MAXN];
  int  flag= 0  ;
 
  //  栈中存位置以及遍历时所走的方向,打印时可以显示出来
  //  栈的元素节点  
typedef  struct   Node{
      int   x;
      int   y;
      struct  Node * next;
}Node;
 
typedef Node * Stack;      //  定义数据结构栈 Stack 

 /*  ……………………………栈函数……………………………  */ 
 //  -----------创建一个空栈-------------- 
 Stack creakEmptyStack(){
    Stack p;
    p =(Stack) malloc ( sizeof (Node));     //  申请一个空间 
     if  (p){
        p ->next= NULL;
          return   p;
    }

}
 
  //  ------------将元素压入栈---------------- 
 void  push( int  x, int   y,Stack s){
    Stack p;
    p =(Stack) malloc ( sizeof  (Node));
      if (p){                    //  如果申请空间成功则用头插法将元素压入 
        p->x= x;
        p ->y= y;
          if (!s->next) p->next=NULL;   //  如果此时栈里还没有任何元素,则p此时为第一个结点 
         else  p->next=s->next;   //  否则将p插入头结点之后 
        s->next= p;
    }
      else  {
        printf(  "  No space!\n  "  );
    }
}
 
  //  -------------检测栈是否为空-------------- 
 int  isEmpty(Stack s){            //  为空则返回1,不为空返回0 
     if (s->next==NULL)  return   1  ;
      else   return   0  ;
}
  //  --------------将元素弹出栈---------------- 
 void   pop(Stack s){
    Stack p;
    p =s-> next;
      if (p-> next){
        s ->next=p-> next;
          free  (p);
    }
      else   return  ;
}
  //  ------------取栈顶元素------------------ 
 Node top(Stack s){
    Node t;
      //  判断是否为空,若不为空则返回 
    t=*(s-> next);
      return   t;
}
 
  void  mazePath( int  x, int  y, int  endx, int  endy, int  n, int   m,Stack s);
  void  printPath(Stack s, int  n, int   m);
 
  int   main()
{
      int   n,m,i,j,xa,xb,ya,yb,ox;
      //  --------------建立迷宫-------------- 
    printf( "  请输入迷宫大小:(长、宽)\n  "  );
    scanf(  "  %d%d  " ,&n,& m);
      if (n<= 20 &&m<= 20  ){
        printf(  "  请选择构建迷宫的方式:\n0.随机生成迷宫\n1.手动输入迷宫\n  " );  //  实际上不是0就可以手动输入 
        scanf( "  %d  " ,& ox);
          for (i= 0 ;i<n;i++ ){
              for (j= 0 ;j<m;j++ ){
                  if (!ox)maze[i][j]=rand()% 2 ;     //  这里为伪随机数 
                 else  scanf( "  %d  " ,& maze[i][j]);
            }
        }
         printf(  "  \n  "  );
          //  ----------输出构建迷宫------------- 
        printf( "  生成的迷宫如下:\n  "  );
          for (i= 0 ;i<n;i++ ){
              for (j= 0 ;j<m;j++ ){
                printf(  "  %d    "  ,maze[i][j]);
            }
            printf(  "  \n  "  );
        }
 
        printf(  "  请输入起点及终点:\n  "  );
        scanf(  "  %d%d%d%d  " ,&xa,&ya,&xb,& yb);
        
          //  标记起点 
        maze[xa- 1 ][ya- 1 ]= 2  ;                        
 
          //  创建一个空栈 
        Stack s= creakEmptyStack();

        mazePath(xa - 1 ,ya- 1 ,xb- 1 ,yb- 1  ,n,m,s);
        printf(  "  最短路径长度为:%d  "  ,MIN);
          if (!flag) printf( "  没有成功找到路径\n  "  );
    }
      else  printf( "  输入数据超出迷宫范围\n  "  );
}
 
  //  -----------遍历迷宫寻找路径(dfs)------------ 
 void  mazePath( int  x, int  y, int  endx, int  endy, int  n, int   m,Stack s){
      int   newx,newy,i;
    Node t;
      for (i= 0 ;i< 4 ;i++ ){
        newx =x+direction[i][ 0  ];
        newy =y+direction[i][ 1  ];
          if (newx>= 0 &&newx<n&&newy>= 0 &&newy<m&&maze[newx][newy]== 0 ){     //  下一个路能走  
             push(newx,newy,s);
            maze[newx][newy] = 2  ;
              if (newx==endx&&newy==endy){ //  走到出口  
                flag++ ;
                printPath(s,n,m);
                maze[newx][newy] = 0  ;
                pop(s);
            }
              else  {
                mazePath(newx,newy,endx,endy,n,m,s);   //  开始递归  
             }
        }
    }
    maze[x][y] = 0 ;    //  遍历完四个方向之后回溯前将自己赋为空 
     pop(s);
}
 
  //  -------------打印迷宫路径----------------- 
 void  printPath(Stack s, int  n, int   m){
      int  cont = 0 ;     //  计算路径长度 
    s=s-> next;
      int  i= 0 ,j= 0  ;
    printf(  "  第%d条路径为:\n  "  ,flag);
      for (i= 0 ;i<n;i++){                          //  按图形输出 
         for (j= 0 ;j<m;j++ ){
              if (maze[i][j]== 2 ) printf( "  *    "  );
              else  printf( "  %d    "  ,maze[i][j]);
        }
        printf(  "  \n  "  );
    }
      while (s->next){                           //  将栈中的元素输出为直观路径 
        printf( "  (%d,%d)->  " ,s->x+ 1 ,s->y+ 1  );
        s =s-> next;
        cont ++ ;
    }
    printf(  "  (%d,%d)  " ,s->x+ 1 ,s->y+ 1  );
    cont ++ ;
      if (cont<MIN) MIN= cont; 
    printf(  "  \n  "  );
    printf(  "  路径长度为:%d\n\n  "  ,cont);
}   

 

测试样例:

 

 

查看更多关于数据结构与算法大作业:走迷宫程序(C语言,DFS)(代码以及思路)的详细内容...

  阅读:20次