栈解决迷宫求解问题
标签(空格分隔): 栈、回溯算法
一、引入
-
找迷宫通路需要使用回溯法,找迷宫通路是对回溯法的一个很好的应用,实现回溯的过程用到数据结构—栈! -
回溯法:对一个包括有很多个结点,每个结点有若干个搜索分支的问题,把原问题分解为若干个子问题求解的 算法;当搜索到某个结点发现无法再继续搜索下去时,就让搜索过程回溯(回退)到该节点的前一个结点,继续 搜索该节点外的其他尚未搜索的分支;如果发现该结点无法再搜索下去,就让搜索过程回溯到这个结点的前一 结点继续这样的搜索过程;这样的搜索过程一直进行到搜索到问题的解或者搜索完了全部可搜索分支没有解存 在为止。
二、栈的特点
其中,base 指向栈底,top 指向栈顶。 注意:栈只能在一端操作,后进先出,这是栈的关键特征,也就是说不允许在中间查找、取值、插入、删除等 操作。
三、具体实现
- 顺序栈的构建:
这里将顺序栈的实现代码都写在头文件maze.h中,用于等下迷宫求解
#pragma once
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100
typedef struct _Position{
int _x;
int _y;
}Position;
#define MaxSize 128
typedef Position ElemType;
typedef struct _SqStack{
ElemType *base;
ElemType *top;
}SqStack;
bool InitStack(SqStack &S)
{
S.base = new ElemType[MaxSize];
if (!S.base)
return false;
S.top=S.base;
return true;
}
bool PushStack(SqStack &S, ElemType e)
{
if (S.top-S.base == MaxSize)
return false;
*(S.top++) = e;
return true;
}
bool PopStack(SqStack &S, ElemType &e)
{
if (S.base == S.top){
return false;
}
e = *(--S.top);
return true;
}
ElemType* GetTop(SqStack &S)
{
if (S.top != S.base){
return S.top - 1;
}else{
return NULL;
}
}
int GetSize(SqStack &S){
return (S.top-S.base);
}
bool IsEmpty(SqStack &S){
if (S.top == S.base){
return true;
}else{
return false;
}
}
void DestoryStack(SqStack &S){
if(S.base){
free(S.base);
S.base = NULL;
S.top = NULL;
}
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "maze.h"
#include <assert.h>
#define ROW 6
#define COL 6
typedef struct _Maze{
int map[ROW][COL];
}Maze;
void InitMaze(Maze* m, int map[ROW][COL])
{
for (int i = 0;i< ROW ;++i)
{
for (int j = 0; j < COL; ++j)
{
m->map[i][j] = map[i][j];
}
}
}
void PrintMaze(Maze* m)
{
for (int i = 0; i < ROW; ++i)
{
for (int j = 0; j < COL; ++j)
{
printf("%d ",m->map[i][j]);
}
printf("\n");
}
printf("\n");
}
int IsValidEnter(Maze* m, Position cur)
{
assert(m);
if ((cur._x == 0 || cur._x == ROW - 1)
|| (cur._y == 0 || cur._y == COL - 1)
&& (m->map[cur._x][cur._y] == 1))
return 1;
else
return 0;
}
int IsNextPass(Maze* m,Position cur, Position next)
{
assert(m);
if(((next._x == cur._x) && ((next._y == cur._y+1)||(next._y ==
cur._y-1)))
||((next._y == cur._y) && ( (next._x == cur._x+1)||(next._x ==
cur._x-1)))){
if (((next._x >= 0 && next._x < ROW) || (next._y >= 0 && next._y
< COL))
&&(m->map[next._x][next._y] == 1)){
return 1;
}
}
return 0;
}
int IsValidExit(Maze* m, Position cur,Position enter)
{
assert(m);
if ((cur._x != enter._x || cur._y != enter._y)
&& ((cur._x == 0 || cur._x == ROW - 1)
|| (cur._y == 0 || cur._y == COL - 1)))
{
return 1;
}
else
return 0;
}
int PassMaze(Maze* m,Position enter,SqStack* s)
{
assert(m && IsValidEnter(m,enter) == 1);
Position cur = enter;
Position next;
PushStack(*s, cur);
m->map[cur._x][cur._y] = 2;
while (!IsEmpty(*s)) {
cur = *GetTop(*s);
if (IsValidExit(m,cur,enter) == 1)
return 1;
next = cur;
next._y = cur._y - 1;
if (IsNextPass(m, cur, next) == 1)
{
PushStack(*s, next);
m->map[next._x][next._y] = m->map[cur._x][cur._y] + 1;
continue;
}
next = cur;
next._x = cur._x - 1;
if (IsNextPass(m,cur,next) == 1)
{
PushStack(*s,next);
m->map[next._x][next._y] = m->map[cur._x][cur._y]+1;
continue;
}
next = cur;
next._y = cur._y + 1;
if (IsNextPass(m, cur,next) == 1)
{
PushStack(*s, next);
m->map[next._x][next._y] = m->map[cur._x][cur._y] + 1;
continue;
}
next = cur;
next._x = cur._x + 1;
if (IsNextPass(m, cur,next) == 1)
{
PushStack(*s, next);
m->map[next._x][next._y] = m->map[cur._x][cur._y] + 1;
continue;
}
Position tmp;
PopStack(*s, tmp);
}
return 0;
}
int main()
{
int map[ROW][COL] = {
0,0,1,0,0,0,
0,0,1,1,1,0,
0,0,1,0,0,0,
0,1,1,1,1,0,
0,0,1,0,1,0,
0,0,0,0,1,0
};
Maze m;
Position enter;
enter._x = 0;
enter._y = 2;
InitMaze(&m, map);
PrintMaze(&m);
SqStack s;
InitStack(s);
int ret = PassMaze(&m,enter,&s);
if(ret){
printf("恭喜你!终于找到了出口~\n");
}else {
printf("不是我笨!实在没有出口~\n");
}
PrintMaze(&m);
system("pause");
return 0;
}
四、输出结果:
- 打印初始迷宫,1代表当前位置可以到达,0代表不可到达。
- 代码中将迷宫的入口地址(合法的入口地址情况下)设为2,将入口地址压栈,每个节点有四个方向可走,按照左、上、右、下的顺序遍历。都走不通的话回退到上一个位置,将栈顶元素出栈即可。
- 下一个位置在数组中的值是当前位置在数组中的值加1(回退的情况除外,只有在遍历未走过的位置才成立)。
实际路径:2-3-4-5-4-3-4-5-6-5-6-7-8-9
|