零、注意要素 1、在迷宫周围需要设置围墙(一圈的1) 2、每个点的走动,需要记录方向,(x,y,方向) 3、如果某点遇到围堵,回退,那么需要标记这个点是不通的。会退后的下一点再往该方向查找时,这一点是不通的,那么那一点需要判断其他方向,如果其他方向也不同则回溯,并且标记那一点也为不通的。 4、stack的topPointer问题,topPointer是指向最上面的数据的上一个空间,
void PUSH(stackNode node,mazeStack *stack) { stack->nodeList[stack->top++]=node; }
所以说当判断当前是否为空时,则如果top 的值为初始化的值,则为空。例如初始化为1,那么当top为1时,则栈为空,因为如果有一个元素的话,执行了stack->nodeList[stack->top++]=node;后top的值为2。 一般top初始化为0,所以判断空时,判断小于等于0;
int Empty(mazeStack *stack) { if(stack->top<=0) { return TRUE; } return FALSE; }
这样可以理解如果退栈是,需要先将top-1,然后读取当前栈的数据,这样就少了一个数据,同时top仍然指向第一个元素的上一个位置。
int POP(stackNode *node, mazeStack *stack) { if(stack->top<=0) return FALSE; *node=stack->nodeList[--stack->top]; return TRUE; }
5、在这个代码中 Mask 和 Stack是不冲突的,他们之间是没有直接关联,即使Mask节点置为1,stack仍然能够退栈(这是当时迷糊很久的事,应该看到他们的独立性)
一、找路的思想 伪代码如下
将入口点压栈; while(堆栈不为空) { POP得到栈顶的元素1; for(从 向右;一直到向上 ;逆时针更改方向) { 得到新的坐标 if(不是墙壁 而且 没有来过) { 将之前的位置记录(元素1)压栈; 踩过去,将当前的位置记录 压栈。 if(到达出口) 返回 退出 方向 for循环。 } } }
二、源代码
#include "stdafx.h" #include <stdio.h> #include <stdlib.h> /*需要注意的是:当为0 的不同情况,需要有另外的标志表示它是不同的,要不然会老早重复的错误路径*/ #define MAZE_SIZE 5 #define START_X 1 #define START_Y 1 #define END_X MAZE_SIZE #define END_Y MAZE_SIZE #define DONE 0 #define NOTDONE -1 #define TRUE 0 #define FALSE -1 #define FRESH 0 #define OLD 1 #define DIRECTION_MAX_COUNT 4 typedef enum{Right,Down,Left,Up}Direction; typedef enum{YES,NO}MARK_TAG; int Maze[MAZE_SIZE+2][MAZE_SIZE+2]; int Mask[MAZE_SIZE+2][MAZE_SIZE+2]; typedef struct{ Direction dir; int dx; int dy; }moveType; moveType Move[4]; typedef struct { int x; int y; }Pos; typedef struct{ Pos pos; Direction direction; int order; }stackNode; typedef struct{ stackNode *nodeList; int top; int bottom; }mazeStack; void initStack(mazeStack *stack) { stack->nodeList=(stackNode * )malloc((MAZE_SIZE*MAZE_SIZE+1)*sizeof(stackNode));//top=0 is empty and is the empty test pos stack->top=0; stack->bottom=0; } void PUSH(stackNode node,mazeStack *stack) { stack->nodeList[stack->top++]=node; } int POP(stackNode *node, mazeStack *stack) { if(stack->top<=0) return FALSE; *node=stack->nodeList[--stack->top]; return TRUE; } int Empty(mazeStack *stack) { if(stack->top<=0) { return TRUE; } return FALSE; } Pos getNextPos() { Pos nextPos; return nextPos; } int findThePath(mazeStack * stack) { Pos curPos; curPos.x=START_X; curPos.y=START_Y; int order=1; /*pseudo code belowe*/ Pos nextPos; stackNode node; node.pos=curPos; node.direction=Right; node.order=order++; PUSH(node,stack); Mask[node.pos.x][node.pos.y]=OLD; int dx,dy,dr,g,h; Direction dir; int i; /*pseudo code */ /* 将入口点压栈; while(堆栈不为空) { POP得到栈顶的元素1; for(从 向右;一直到向上 ;逆时针更改方向) { 得到新的坐标 if(不是墙壁 而且 没有来过) { 将之前的位置记录(元素1)压栈; 踩过去,将当前的位置记录 压栈。 if(到达出口) 返回 退出 方向 for循环。 } } } /* */ while(Empty(stack)==FALSE) { if(POP(&node,stack)!=FALSE) { node.order=--order; for(i=0;i<DIRECTION_MAX_COUNT;i++) { g=node.pos.x+Move[i].dx; h=node.pos.y+Move[i].dy; dir=Move[i].dir; if(Maze[g][h]==0 && Mask[g][h]==FRESH) { node.direction=dir; PUSH(node,stack); Mask[g][h]=OLD; node.pos.x=g; node.pos.y=h; node.direction=Right; node.order=order++; PUSH(node,stack); if(g==END_X &&h==END_Y) return TRUE; break; } } } } return FALSE; } void initMaze() { /*creat the outside wall*/ for(int i=0;i<MAZE_SIZE+2;i++) { Maze[0][i]=1; Maze[MAZE_SIZE+1][i]=1; } for(int j=1;j<MAZE_SIZE+1;j++) { Maze[j][0]=1; Maze[j][MAZE_SIZE+1]=1; } /**/ for(int i=1;i<MAZE_SIZE+1;i++) for(int j=1;j<MAZE_SIZE+1;j++) { scanf("%d",&Maze[i][j]); } } void initMask() { for(int i=0;i<MAZE_SIZE+2;i++) for(int j=0;j<MAZE_SIZE+2;j++) Mask[i][j]=FRESH; } void initMove() { Move[0].dir=Right; Move[0].dx=0; Move[0].dy=1; Move[1].dir=Down; Move[1].dx=1; Move[1].dy=0; Move[2].dir=Left; Move[2].dx=0; Move[2].dy=-1; Move[3].dir=Up; Move[3].dx=-1; Move[3].dy=0; } int main() { mazeStack stack; initMaze(); initMask(); initMove(); initStack(&stack); if(findThePath(&stack)==TRUE) { for(int i=stack.bottom;i<stack.top;i++) printf("(%d,%d)/n",stack.nodeList[i].pos.x-1,stack.nodeList[i].pos.y-1); } else { printf("No FInd/n"); } scanf("%d",&Maze[0][0]); return 0; }
三、运行效果
1、有通路情况
2、无路情况
四、可改进部分 1、迷宫的size,以及将方形的迷宫可以改为矩形的迷宫(不一定是正方形) 这些可以更改MAZE_SIZE宏、END_X、END_Y来达到,并添加长度、宽度 2、可以改进方向,由4个方向,改为8个方向。 typedef enum{Right,Down,Left,Up,NorthEast,SouthEast ,SouthWest,NorthWest}Direction; #define DIRECTION_MAX_COUNT 8 修改void initMove()以配合8个方向。