"栈"应用——求解迷宫
迷宫的数字表示:0表示通道,1表示墙,inP表示入口坐标,outP表示出口,
如图入口坐标为(1,1)出口为(8,8)
static int item[10][10] = {
{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}
};
static const POS inPos = {1,1},outPos ={8,8};
计算方法:若当前位置可通,则纳入当前路径,做标记(2)并继续朝下一个位置探索,即切换下一位置为当前位置
如此重复直至道道出口;
若当前位置不可通,则应顺着来的方向退回前一通道快,然后朝着除来向之外的其它方向继续搜索;
若该通道快四周4个方向均不可通,则应从当前路径上删除该通道块.
然后探测向下位置,发现可通,则把向下位置作为当前位置,(5,1)做压栈.
以(5,1)为当前位置,进行探测
发现向下方向可通,则将(6,1)入栈,同样的(7,1)入栈
然后,发现其它三个方向都不可通,标记为走不通(3),且(上)这个位置被标记为(2)已走过,所以(7,1)退栈,退回到(6,1),(6,1)退栈,将方向转变为下一个方向进行压栈。(即寻找下一个路口)

然后我们还是发现,第三个位置(右边)走不通,上面(5,1)被标记为已走过(2),所以退栈,
(5,1)退栈,搜索四个方向,发现左边不可通,下面(6,1)走过,且四个方向都不通,已标记为(3),开始搜索第三个方向(右侧)(5,2)可通,把(5,2)当作当前位置,压栈。然后继续如此迭代下去。
下面可以看下数据结构的定义:
data.h
#ifndef _DATA_H
#define _DATA_H
//typedef int ElemType;
typedef struct
{
int y;
int x;
}POS;
//栈的类型
typedef struct
{
int sno; //编号
POS seat; //位置
int di; //朝向
}ElemType;
#endif
接下来的代码也贴下:
main.h
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<conio.h>
#include"stack.h"
//用二维数组构造迷宫的图形
static int item[10][10] = {
{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}
};
//定义迷宫的位置、出口,作为成功的判断依据。
static const POS inPos = {1,1},outPos ={8,8};
//判断是否可通,可通=0,不可通=1
int IsPass(POS curP){
return item[curP.y][curP.x] == 0 ? 1 : 0;
}
//获得下一个方向,di=0,1,2,3分别代表左下右上
POS NextPos(POS curP,int di)
{
POS p = curP;
switch(di)
{
case 0:
p.x--;
break;
case 1:
p.y++;
break;
case 2:
p.x++;
break;
case 3:
p.y--;
}
return p;
}
//测试打印
void PrintItem(POS curP)
{
int i,j;
//清屏
system("cls");
for(i=0;i<10;i++)
{
for(j=0;j<10;j++)
{
//打印当前位置
if(i == curP.y && j == curP.x)
{
printf("@");
continue;
}
// *代表墙,空格代表可通
if(item[i][j] == 1)
printf("*");
else
printf(" ");
}
printf("\n");
}
}
void main()
{
ElemType e;
int setp = 1;
POS curPos = inPos;
STACK *s = InitStack();
PrintItem(inPos);
getch();
do
{
//1.判断当前位置是否可通
if(IsPass(curPos))
{
//存当前步到e
e.sno = setp;
//它的方向
e.di = 0;
//他的坐标
e.seat = curPos;
Push(s,&e);
//留下走过的足迹2代表走过
item[curPos.y][curPos.x] = 2;
//判断当前位置是否是出口。
if(curPos.y == outPos.y && curPos.x == outPos.x)
{
PrintItem(curPos);
//找到了
printf("OK");
break;
}
//打印当前位置
PrintItem(curPos);
getch();
//找下一个位置
curPos = NextPos(curPos,0);
//把它的步骤递增
setp++;
}else{
Pop(s,&e);
//如果节点每个方向找完都没通,且栈中还有元素就返回上一个
while(e.di == 4 && !IsEmpty(s))
{
//把都不能走通的位置做一个标志
item[curPos.y][curPos.x] = 3;
Pop(s,&e);
}
if(e.di < 3)
{
//方向指向它的下一个
e.di++;
//重新压栈(原来的位置,下一个方向)
Push(s,&e);
curPos = NextPos(e.seat,e.di);
}
}
}while(!IsEmpty(s));
}
分析下算法。
do
{
if(若当前位置可通)
{
将当前位置插入栈顶
若该位置是出口,则结束
否则切换当前位置的第一方向方块为当前位置
}else{
若栈不空切栈顶位置尚有其它方向未经探索
则取栈顶方块的下一方向的相邻方块为当前方块
若栈不空且栈顶位置的四周均不可通则
{
删去栈顶位置;
若栈不空,则重新测试新的栈的位置,直到找到
一个可通的相邻块或出栈至栈空
}
}
}while(栈不空);
思成老师引入了#include<conio.h>在代码中插入getch()使输出暂停
引入了#include<stdlib.h>通过函数system(“cls”)清屏,使得每找到一个可通的位置时,或者从不可通的路径退回到这个位置时都显示一张图。并且以@表示当前位置。









浙公网安备 33010602011771号