堆栈实现迷宫算法
/**
* 迷宫问题
* 迷宫用二维数组存储,0可走而1不可走
* 1,1,1,1,1,1,1,1,1,1,1
* 1,0,1,0,0,1,1,1,0,0,1
* 1,0,0,0,0,0,1,0,0,1,1
* 1,0,1,1,1,0,0,0,1,1,1
* 1,0,0,0,1,0,1,1,0,1,1
* 1,1,0,0,1,0,1,1,0,0,1
* 1,1,1,0,0,0,0,0,0,0,1
* 1,1,1,1,1,1,1,1,1,1,1
*/
#include <stdio.h>
#include <malloc.h>
typedef struct{
int x,y;//xy代表东南西北移动的数据
}Direction;
typedef struct{
int position_x,position_y;
int direct;
}Box;
struct Stack{
int MAXNUM;
int top_position;
Box* path;
};
typedef struct Stack* PStack;
PStack createEmptyStack(int size){
PStack s = (PStack)malloc(sizeof(struct Stack));
if(s != NULL)
{
s->path = (Box*)malloc(sizeof(Box)*size);
if(s->path)
{
s->MAXNUM = size;
s->top_position = -1;
return s;
}
printf("Box 数组创建失败\n");
}
printf("Stack创建失败\n");
}
int isEmptyStack(PStack s){
if(s->top_position == -1) return 1;
return 0;
}
void push(PStack s,Box temp){
if(s->top_position == (s->MAXNUM -1))
{
printf("Stack满载\n");
return;
}
s->top_position++;
s->path[s->top_position] = temp;
}
void pop(PStack s){
if(isEmptyStack(s))
{
printf("空栈无法pop!\n");
return;
}
s->top_position -= 1;
}
Box getTop(PStack s)
{
if(isEmptyStack(s))
{
printf("空栈无数据\n");
}
return s->path[s->top_position];
}
void findExit(int map[8][11],Direction direction[]){
PStack s = createEmptyStack(6*9); // s 用来存放路径的栈,大小为迷宫实际大小
int x,y,d; //当前处理单元的x,y坐标以及方向度d
int line,col; //下一个处理单元的行列坐标
Box temp; //用于存储处理过的单元的x,y坐标以及方向度d的box,压入栈中的
map[1][1] = -1; //起始位置为1,1,并且做已走过的标记-1
temp.position_x = 1;
temp.position_y = 1;
temp.direct = -1; //-1,表示还没有探寻任何一个方向
push(s,temp); //起点先压入栈中
while(!isEmptyStack(s))//当栈不空时,还有找到出口的可能
{
temp = getTop(s); //当所有方向试探完毕,先用暂存获得最
pop(s); //当所有方向试探完毕,则弹出最上方的元素,因为起跳的栈不在栈中
//当前处理元素的数据即目前最顶层栈的数据
x = temp.position_x;
y = temp.position_y;
d = temp.direct + 1;
while(d<4)
{
//执行探寻操作 不同的d代表不同方向
line = x + direction[d].x;
col = y + direction[d].y;
if(map[line][col] == 0) //如果下个单元可走
{
map[line][col] = -1; //标记为走过
temp.position_x = x;
temp.position_y = y;
temp.direct = d;
push(s,temp); //将起跳单元压入栈中,并将下个栈当作新起点,也就是正在处理的单元
x = line;
y = col;
d = -1;
}
if(line == 6 && col == 9) //如果找到了出口
{
map[line][col] = -1; //标记为走过
temp.position_x = line;
temp.position_y = col;
temp.direct = d;
push(s,temp);
while (!isEmptyStack(s))
{
temp = getTop(s);
pop(s);
printf("(%d,%d)",temp.position_x,temp.position_y);
}
return;
}
d = d + 1;
}
}
printf("没找到出口\n");
}
int main() {
int map[8][11]={{1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,0,0,1,1,1,0,0,1},
{1,0,0,0,0,0,1,0,0,1,1},
{1,0,1,1,1,0,0,0,1,1,1},
{1,0,0,0,1,0,1,1,0,1,1},
{1,1,0,0,1,0,1,1,0,0,1},
{1,1,1,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1,1}};
Direction direction[4];
//东
direction[0].x = 0;
direction[0].y = 1;
//南
direction[1].x = 1;
direction[1].y = 0;
//西
direction[2].x = 0;
direction[2].y = -1;
//北
direction[3].x = -1;
direction[3].y = 0;
findExit(map,direction);
return 0;
}
算法实现的关键
1.过多的if语句不利于判断,此时要想办法重构方法,去实现多if的情况。题目中的东南西北探寻,就被封装在了一个结构体数组中。
因为有4个方向需要探寻,所以用while循环即可控制
2.因此,栈中的元素类型也要发生相应的变化,我称作Box类型:
3.为什么在算法核心中,起点压入了栈中却又要弹出来?它究竟服务了什么?
首先,压入起点,是为了进入第一层循环。
至于为什么弹出来,我打个比方:
如果将迷宫理解为跳板迷宫,进入下一个单元必须是使用跳跃的动作,并且跳起的同时会将起跳单元踩出痕迹(也就是压入栈中)。算法中有两个概念,当前处理单元,下一个单元。**他们两个都是不在栈中的。**当前处理点就是你要起跳的点,下一个单元就是你渴望着陆的点。这么做的原因,是因为当走进死胡同时,我们需要退栈。当你跳入了死胡同的尽头,此时死胡同尽头还没有被压入栈中,因为我们并没有起跳,此时以死胡同尽头为起跳点,开始试探,发现四个方向都已经无法跳跃或者已经走过。这是需要退栈,取得上一个起跳点的所有数据,包括坐标,以及最关键的方向度,因为上一个点有可能没有考虑完所有的方向,取出所有的数据后,再将栈顶元素,也就是上一个起跳点弹出,相当于去除了原先起跳点的起跳很急,时光倒流回到了那个起跳点。再开始重新接着判断没有判断的方向,这样就可以保证探寻到每一个方向。这也就是能退栈,回到上一点的原因。