迷宫的数字表示: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”)清屏,使得每找到一个可通的位置时,或者从不可通的路径退回到这个位置时都显示一张图。并且以@表示当前位置。