基于堆栈的迷宫问题

问题描述:

    迷宫是一个矩形区域,它仅有一个入口和一个出口。在迷宫的内部不能穿越的墙或障碍,也包含一些可以行走的通路。现在从入口出发,想要到达出口。用回溯思想设计算法,找到出口。

基本要求:

  1. 使用堆栈实现迷宫中寻找路径算法;
  2. 只有4个方向,分别为东、南、西、北;
  3. 不能走到迷宫外,‘#’代表障碍物,无法通行;
  4. 提供测试代码,给出测试结果;

算法思想:

       回溯算法实际上是一个类似枚举的探索尝试过程,主要是在探索尝试过程中寻找问题的解,当发现当前不满足求解条件时,就“回溯”返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标。就退回一步重新选择,这种走不通就退回再走的方法为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法的美称”。

       在这里运用回溯思想(堆栈实现),在迷宫中找路,解决迷宫问题。本算法主要包括:回溯寻找路径部分。

测试迷宫:

char maze[MaxSize][MaxSize]=
		   {{'G', '.', '#', '#', '#', '#', '#', '#', '#', '#','.','.','.','#','#','#'},
			{'#', '.', '#', '#', '#', '.', '#', '.', '.', '#','.','.','.','.','.','#'},
			{'#', '.', '#', '#', '#', '.', '#', '.', '#', '#','.','#','.','.','.','#'},
			{'#', '.', '#', '#', '#', '.', '.', '.', '.', '#','.','#','#','.','#','#'},
			{'#', '.', '.', '.', '.', '.', '.', '.', '.', '.','.','.','#','.','#','#'},
			{'#', '.', '.', '.', '.', '.', '.', '.', '.', '.','.','.','#','.','#','#'},
			{'#', '.', '.', '.', '#', '#', '#', '#', '#', '.','.','.','#','.','.','#'},
			{'#', '.', '.', '.', '.', '.', '.', '#', '.', '.','.','.','#','.','.','#'},
			{'#', '.', '.', '.', '.', '.', '.', '#', '.', '.','.','.','.','#','.','#'},
			{'#', '.', '#', '#', '#', '#', '#', '#', '.', '.','.','.','.','#','.','#'},
			{'#', '.', '#', '.', '.', '.', '.', '.', '.', '.','.','.','.','#','.','#'},
			{'#', '.', '#', '.', '.', '.', '.', '.', '#', '.','.','.','.','#','.','#'},
			{'#', '.', '#', '.', '#', '#', '#', '.', '#', '.','#','#','.','.','.','#'},
			{'#', '.', '.', '.', '#', '#', '#', '.', '#', '.','#','#','.','S','.','.'},
			{'#', '.', '.', '.', '#', '#', '#', '.', '#', '.','#','#','.','.','.','.'},
			{'#', '.', '#', '#', '#', '#', '.', '.', '#', '.','.','#','#','#','#','.'},};

注解:

‘ ’where the robot can move (open positions)

 '#' -obstacles (blocked positions)

 'S' -start position

 'G' -goal 

回溯路径寻找:

  从起点开始进行路径寻找。在添加边界后每个位置有四种可能的移动方向:右、下、左和上。判断当前位置的右、下、左和上位置能否通行,即查看迷宫对应位置是否为0。若为0则可通行,将当前位置移动到对应方向,原位置入堆栈。若为1则不可通行,尝试下一个方向。若四个方向均不可通行,则当前栈顶元素出栈,尝试下一个方向。即递归回溯尝试所有的可能位置,直到当前位置等于出口位置。将已通过的位置置1,以免重复走。将走过的路径记录下来,即是寻找的可行路径。本算法将“在搜索过程中某一个时刻所在迷宫地图中的位置“记为“当前位置”,那么求解迷宫路径算法的基本思想是:若“当前位置”可通行,那么将“当前位置”纳入求解路径中(压到栈中),并朝“下一个位置”继续探索,即把“下一位置”切换到“当前位置”,如此重复下去,直到找到出口;如果当前位置不可以通行,则顺着来的方向退回到“前一个通道位置”,然后再朝着其他方向探索下去;如果该通道块的4个方向(东西南北)都不可通,那么就在该路径(栈)中删除该通道位置(删除栈顶元素),再继续退回到“前一个通道位置”继续探索,即再获取栈顶元素作为“当前位置继续上述的重复探索。

总体流程图如下:

这里我们首先定义基本的方向:

这是定义x,y的方向

 这里我们需要写出堆栈的基本数据结构和基本操作:

堆栈里面存取的是当前点的x和y坐标:

typedef struct snode
{
    int x;         //定义该点的x坐标
    int y;         //定义该点的y坐标
    struct snode *next;
}LSNode;

 

 

 

堆栈基本的操作函数

堆栈的程序如下:

#include "stack.h"
//链表初始化函数
void StackInitiate(LSNode **head)
{
    *head = (LSNode *)malloc(sizeof(LSNode));
    (*head)->next = NULL;
}
//判断堆栈是否为空函数
int StackNotEmpty(LSNode *head)
{
    if(head->next == NULL) return 0;
    else return 1;
}
//入栈操作函数
void StackPush(LSNode *head,int x,int y)
{
    LSNode *p;

    p=(LSNode *)malloc(sizeof(LSNode));
    p->x = x;
    p->y = y;
    p->next = head->next;
    head->next = p;
}
//出栈操作函数
int StackPop(LSNode *head,int *x,int *y)
{
    LSNode *p = head->next;
    if(p == NULL)
    {
        printf("堆栈已空,无元素可出!\n");
        return 0;
    }
    head->next = p->next;
    *x = p->x;
    *y = p->y;
    free(p);
    return 1;
}
//取栈顶元素操作函数
int StackTop(LSNode *head,int *x,int *y)
{
    LSNode *p = head->next;
    if(p == NULL)
    {
        printf("堆栈已空出错!\n");
        return 0;
    }
    *x = p->x;
    *y = p->y;
    return 1;
}
//销毁堆栈
void StackDestroy(LSNode *head)
{
    LSNode *p,*p1;
    p = head;
    while(p!=NULL)
    {
       p1 = p;
       p = p->next;
       free(p1);
    }
}

堆栈的头文件如下:

#ifndef _STACK_H
#define _STACK_H
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <math.h>

typedef struct snode
{
    int x;         //定义该点的x坐标
    int y;         //定义该点的y坐标
    struct snode *next;
}LSNode;

void StackInitiate(LSNode **head);
int StackNotEmpty(LSNode *head);
void StackPush(LSNode *head,int x,int y);
int StackPop(LSNode *head,int *x,int *y);
int StackTop(LSNode *head,int *x,int *y);
void StackDestroy(LSNode *head);
#endif // _STACK_H

接下里我们需要定义迷宫位置的结构体及相应的操作函数:

typedef struct{
    int x;       //定义位置的坐标x
    int y;       //定义位置的坐标y
    int east;    //定义东方向的标志位
    int south;   //定义南方向的标志位
    int west;    //定义西方向的标志位
    int north;   //定义北方向的标志位
    int flag;    //定义当前位置是否方位的标志位
}Location;

位置初始化操作函数:

//位置初始化函数.
void LocationInitiate(Location array[],int n)
{
    int i;
    for(i=0;i<n;i++)
    {
        array[i].x = -1;
        array[i].y = -1;
        array[i].east = 0;
        array[i].south = 0;
        array[i].west = 0;
        array[i].north = 0;
        array[i].flag = 0;
    }
}

判断方位是否操作函数:

//判断当前位置是否访问过
int WhetherVisited(int x,int y,Location array[],int n)
{
   int i;
   for(i=0;i<n;i++)
   {
     if(array[i].x==x && array[i].y==y)
     {
         return 1;
     }
   }
   return 0;
}
//东方向是否访问
int WhetherVisitedEast(int x,int y,Location array[],int n)
{
   int i;
   for(i=0;i<n;i++)
   {
     if(array[i].x==x && array[i].y==y && array[i].east)
     {
         return 1;
     }
   }
   return 0;
}
//南方向是否访问
int WhetherVisitedSouth(int x,int y,Location array[],int n)
{
   int i;
   for(i=0;i<n;i++)
   {
     if(array[i].x==x && array[i].y==y && array[i].south)
     {
         return 1;
     }
   }
   return 0;
}
//西方向是否访问
int WhetherVisitedWest(int x,int y,Location array[],int n)
{
   int i;
   for(i=0;i<n;i++)
   {
     if(array[i].x==x && array[i].y==y && array[i].west)
     {
         return 1;
     }
   }
   return 0;
}
//北方向是否访问
int WhetherVisitedNorth(int x,int y,Location array[],int n)
{
   int i;
   for(i=0;i<n;i++)
   {
     if(array[i].x==x && array[i].y==y && array[i].north)
     {
         return 1;
     }
   }
   return 0;
}

找到迷宫起点终点操作函数:

//找到迷宫起点操作函数
int FindMazeStart(char maze[][MaxSize],int x_size,int y_size,int *start_x,int *start_y)
{
    int i,j;
    for(i=0;i<x_size;i++)
    {
        for(j=0;j<y_size;j++)
        {
            if(maze[i][j] =='S')
            {
                *start_x = i;
                *start_y = j;
                 return 1;
            }
        }
    }
    printf("没有找到起点!\n");
    return 0;
}
//找到迷宫终点操作函数
int FindMazeEnd(char maze[][MaxSize],int x_size,int y_size,int *end_x,int *end_y)
{
    int i,j;
    for(i=0;i<x_size;i++)
    {
        for(j=0;j<y_size;j++)
        {
            if(maze[i][j] =='G')
            {
                *end_x = i;
                *end_y = j;
                 return 1;
            }
        }
    }
    printf("没有找到终点!\n");
    return 0;
}

得到优先级操作函数:

这里我们一共有4种位置

这种情况下我们需要向东走或者向南走才能快速的到达终点,判断先是向东走还是向南走,这里我们分别求|end_x-cur_x|与|end_y-cur_y|,然后比较两个的绝对值大小,就能够赋予相应的优先级。

这种情况下我们需要向西走或者向南走才能快速的到达终点,判断先是向东走还是向南走,这里我们分别求|end_x-cur_x|与|end_y-cur_y|,然后比较两个的绝对值大小,就能够赋予相应的优先级。

这种情况下我们需要向北走或者向东走才能快速的到达终点,判断先是向东走还是向南走,这里我们分别求|end_x-cur_x|与|end_y-cur_y|,然后比较两个的绝对值大小,就能够赋予相应的优先级。

这种情况下我们需要向北走或者向西走才能快速的到达终点,判断先是向东走还是向南走,这里我们分别求|end_x-cur_x|与|end_y-cur_y|,然后比较两个的绝对值大小,就能够赋予相应的优先级。

/*
优先级方向函数
东->4
南->3
西->2
北->1
*/
void DirectionPriority(int Priorityflag[],int x,int y,int end_x,int end_y)
{
   int temp_x,temp_y;
   temp_x = end_x - x;
   temp_y = end_y - y;
   if(temp_x>=0 && temp_y>=0)
   {
       if(temp_x>=temp_y)
       {
           Priorityflag[0] = 3;
           Priorityflag[1] = 4;
           Priorityflag[2] = 2;
           Priorityflag[3] = 1;
       }
       else
       {
           Priorityflag[0] = 4;
           Priorityflag[1] = 3;
           Priorityflag[2] = 2;
           Priorityflag[3] = 1;
       }
   }
   else if(temp_x<0 && temp_y>=0)
   {
       temp_x = abs(temp_x);
       if(temp_x>=temp_y)
       {
           Priorityflag[0] = 1;
           Priorityflag[1] = 4;
           Priorityflag[2] = 3;
           Priorityflag[3] = 2;
       }
       else
       {
           Priorityflag[0] = 4;
           Priorityflag[1] = 1;
           Priorityflag[2] = 3;
           Priorityflag[3] = 2;
       }
   }
   else if(temp_x>=0 && temp_y<0)
   {
       temp_y = abs(temp_y);
       if(temp_x>=temp_y)
       {
           Priorityflag[0] = 3;
           Priorityflag[1] = 2;
           Priorityflag[2] = 4;
           Priorityflag[3] = 1;
       }
       else
       {
           Priorityflag[0] = 2;
           Priorityflag[1] = 3;
           Priorityflag[2] = 4;
           Priorityflag[3] = 1;
       }
   }
   else
   {
       temp_x = abs(temp_x);
       temp_y = abs(temp_y);
        if(temp_x>=temp_y)
       {
           Priorityflag[0] = 1;
           Priorityflag[1] = 2;
           Priorityflag[2] = 3;
           Priorityflag[3] = 4;
       }
       else
       {
           Priorityflag[0] = 2;
           Priorityflag[1] = 1;
           Priorityflag[2] = 3;
           Priorityflag[3] = 4;
       }
   }
}

打印路径函数:

//打印路线函数
void PrintMazePath(LSNode *head,int start_x,int start_y,int end_x,int end_y,char maze[][MaxSize],int TransFlag)
{
  LSNode *cur_Node;
  int i,j;
  int cur_x,cur_y;
  char tempmaze[MaxSize][MaxSize];
  cur_Node = head->next;
  if(cur_Node == NULL)
  {
      printf("该堆栈为空,打印路径失败!\n");
      exit(0);
  }
  while(StackNotEmpty(head))
  {
      StackPop(head,&cur_x,&cur_y);
      maze[cur_x][cur_y]='X';
  }
  if(!TransFlag)
  {
    maze[start_x][start_y] = 'S';
    maze[end_x][end_y] = 'G';
    for(i=0;i<MaxSize;i++)
    {
        for(j=0;j<MaxSize;j++)
        {
            printf("%c ",maze[i][j]);
        }
        printf("\n");
    }
  }
  if(TransFlag)
  {
    for(i=0;i<MaxSize;i++)
    {
        for(j=0;j<MaxSize;j++)
        {
           tempmaze[i][j] = maze[j][i];
        }

    }
    tempmaze[start_y][start_x] = 'S';
    tempmaze[end_y][end_x] = 'G';
    for(i=0;i<MaxSize;i++)
    {
        for(j=0;j<MaxSize;j++)
        {
            printf("%c ",tempmaze[i][j]);
        }
        printf("\n");

    }
  }
}

迷宫路径寻找函数:

//迷宫路径寻找函数
void FindMazePath(int start_x,int start_y,int end_x,int end_y,char maze[][MaxSize],int TransFlag)
{
    LSNode *Stack;
    int cur_x,cur_y,cur_east,cur_south,cur_west,cur_north;
    int pre_x,pre_y;
    int LocationCount = 0;
    int LocationFind = 0;
    int PriorityCount = 0;
    int Priorityflag[4]={0,0,0,0};  //定义优先级数组
    Location array[StoreSize];     //定义坐标元素数组

    LocationInitiate(array,StoreSize);//初始化位置结构体
    StackInitiate(&Stack);   //创建一个堆栈
    StackPush(Stack,start_x,start_y);//将起点的x坐标,y坐标入堆栈
    while(StackNotEmpty(Stack))
    {
      StackPop(Stack,&cur_x,&cur_y);
      if(Priorityflag[PriorityCount]==0)
      {
          PriorityCount = 0;
          DirectionPriority(Priorityflag,cur_x,cur_y,end_x,end_y);
      }
      cur_east = WhetherVisitedEast(cur_x,cur_y,array,StoreSize);
      cur_south = WhetherVisitedSouth(cur_x,cur_y,array,StoreSize);
      cur_west = WhetherVisitedWest(cur_x,cur_y,array,StoreSize);
      cur_north = WhetherVisitedNorth(cur_x,cur_y,array,StoreSize);
      if(cur_x == end_x&&cur_y == end_y)
      {
          printf("Finding path successfully!\n");
          StackPush(Stack,cur_x,cur_y);
          break;
      }
      else if((!cur_east)&&(cur_y+1<MaxSize) && maze[cur_x][cur_y+1]!='#'&& Priorityflag[PriorityCount]==4)
      {
            cur_east = 1;//将东方向的标志位置一;
            pre_x = cur_x;
            pre_y = cur_y+1;
            if(!WhetherVisited(pre_x,pre_y,array,StoreSize))
            {

                array[LocationCount].x = pre_x;
                array[LocationCount].y = pre_y;
                array[LocationCount].flag = 1;
                array[LocationCount].west=1;
                LocationCount++;
            }
                for(LocationFind = 0;LocationFind<StoreSize;LocationFind++)
                {
                    if(array[LocationFind].x == cur_x && array[LocationFind].y == cur_y)
                      array[LocationFind].east = 1;
                }
            StackPush(Stack,cur_x,cur_y);
            StackPush(Stack,pre_x,pre_y);
            Priorityflag[PriorityCount]=0;
            continue;
      }
      else if(!cur_south && (cur_x+1<MaxSize) && maze[cur_x+1][cur_y]!='#' && Priorityflag[PriorityCount]==3)
      {
            cur_south = 1;//将南方向的标志位置一;
            pre_x = cur_x+1;
            pre_y = cur_y;
            if(!WhetherVisited(pre_x,pre_y,array,StoreSize))
            {
                array[LocationCount].x = pre_x;
                array[LocationCount].y = pre_y;
                array[LocationCount].flag = 1;
                array[LocationCount].north=1;
                LocationCount++;
            }
                for(LocationFind = 0;LocationFind<StoreSize;LocationFind++)
                {
                    if(array[LocationFind].x == cur_x && array[LocationFind].y == cur_y)
                      array[LocationFind].south = 1;
                }
            StackPush(Stack,cur_x,cur_y);
            StackPush(Stack,pre_x,pre_y);
            Priorityflag[PriorityCount]=0;
            continue;

      }

      else if(!cur_west&&(cur_y-1>=0) && maze[cur_x][cur_y-1]!='#'&&Priorityflag[PriorityCount]==2)
      {
            cur_west = 1;//将西方向的标志位置一;
            pre_x = cur_x;
            pre_y = cur_y-1;
            if(!WhetherVisited(pre_x,pre_y,array,StoreSize))
            {
                array[LocationCount].x = pre_x;
                array[LocationCount].y = pre_y;
                array[LocationCount].flag = 1;
                array[LocationCount].east=1;
                LocationCount++;
            }
                for(LocationFind = 0;LocationFind<StoreSize;LocationFind++)
                {
                    if(array[LocationFind].x == cur_x && array[LocationFind].y == cur_y)
                      array[LocationFind].west = 1;
                }
            StackPush(Stack,cur_x,cur_y);
            StackPush(Stack,pre_x,pre_y);
            Priorityflag[PriorityCount]=0;
            continue;
      }
      else if(!cur_north && (cur_x-1>=0) && maze[cur_x-1][cur_y]!='#'&&Priorityflag[PriorityCount]==1)
      {
            cur_north = 1;//将北方向的标志位置一;
            pre_x = cur_x-1;
            pre_y = cur_y;
            if(!WhetherVisited(pre_x,pre_y,array,StoreSize))
            {
                array[LocationCount].x = pre_x;
                array[LocationCount].y = pre_y;
                array[LocationCount].flag = 1;
                array[LocationCount].south=1;
                LocationCount++;
            }
                for(LocationFind = 0;LocationFind<StoreSize;LocationFind++)
                {
                    if(array[LocationFind].x == cur_x && array[LocationFind].y == cur_y)
                      array[LocationFind].north = 1;
                }
            StackPush(Stack,cur_x,cur_y);
            StackPush(Stack,pre_x,pre_y);
            Priorityflag[PriorityCount]=0;
      }
      else
      {
                if(Priorityflag[PriorityCount]!=0&&PriorityCount<3)
                {
                     PriorityCount++;
                     StackPush(Stack,cur_x,cur_y);
                }
                else
                {
                    PriorityCount = 0;
                }
      }
    }

    if(cur_x!=end_x||cur_y!=end_y)   //判断是否有路径从起点到终点
    {
        printf("There are not paths to the end!\n");
        exit(0);
    }
    PrintMazePath(Stack,start_x,start_y,end_x,end_y,maze,TransFlag);
    StackDestroy(Stack);
}

迷宫头文件定义如下:

#ifndef _MAZE_H
#define _MAZE_H
#include "stack.h"
#define MaxSize 16
#define StoreSize 256
typedef struct{
    int x;
    int y;
    int east;
    int south;
    int west;
    int north;
    int flag;
}Location;


/*内部调用函数*/
void LocationInitiate(Location array[],int n);
int WhetherVisited(int x,int y,Location array[],int n);
void PrintMazePath(LSNode *head,int start_x,int start_y,int end_x,int end_y,char maze[][MaxSize],int TransFlag);
int WhetherVisitedEast(int x,int y,Location array[],int n);
int WhetherVisitedSouth(int x,int y,Location array[],int n);
int WhetherVisitedWest(int x,int y,Location array[],int n);
int WhetherVisitedNorth(int x,int y,Location array[],int n);
void DirectionPriority(int Priorityflag[],int x,int y,int end_x,int end_y);
/*外部调用函数*/
void FindMazePath(int start_x,int start_y,int end_x,int end_y,char maze[][MaxSize],int TransFlag);
int FindMazeEnd(char maze[][MaxSize],int x_size,int y_size,int *end_x,int *end_y);
int FindMazeStart(char maze[][MaxSize],int x_size,int y_size,int *start_x,int *start_y);
#endif // _MAZE_H

主函数如下:

#include "stack.h"
#include "maze.h"
extern char maze[MaxSize][MaxSize];
char Transmaze [MaxSize][MaxSize];
int main()
{
    int start_x,start_y;
    int end_x,end_y;
    int i,j;
    int TransFlag = 0;
    if(FindMazeStart(maze,MaxSize,MaxSize,&start_x,&start_y)&&FindMazeEnd(maze,MaxSize,MaxSize,&end_x,&end_y))
    {
        if(start_y <= end_y || start_x <= end_x)
        {
            printf("Original maze:\n");
            for(i=0;i<MaxSize;i++)
            {
                for(j=0;j<MaxSize;j++)
                {
                    printf("%c ",maze[i][j]);
                }
                printf("\n");
            }
            printf("\n");
            FindMazePath(start_x,start_y,end_x,end_y,maze,TransFlag);
        }
        else
        {
           TransFlag = 1;
           printf("Original maze:\n");
           for(i=0;i<MaxSize;i++)
            {
                for(j=0;j<MaxSize;j++)
                {
                    printf("%c ",maze[i][j]);
                }
                printf("\n");
            }
            printf("\n");
            printf("Transposition maze:\n");
            for(i=0;i<MaxSize;i++)
            {
                for(j=0;j<MaxSize;j++)
                {
                    Transmaze[j][i] = maze[i][j];
                }
            }
            for(i=0;i<MaxSize;i++)
            {
                for(j=0;j<MaxSize;j++)
                {
                    printf("%c ",Transmaze[i][j]);
                }
                printf("\n");
            }
            printf("\n");
            FindMazeStart(Transmaze,MaxSize,MaxSize,&start_x,&start_y);
            FindMazeEnd(Transmaze,MaxSize,MaxSize,&end_x,&end_y);
            FindMazePath(start_x,start_y,end_x,end_y,Transmaze,TransFlag);
        }
    }
    else
        printf("没有起点或者没有终点,寻找路径失败\n");
    return 0;
}

最终结果:

完。

猜你喜欢

转载自blog.csdn.net/qq_40598185/article/details/85276334
今日推荐