您的位置:首页 > 理论基础 > 数据结构算法

数据结构应用实例#栈#迷宫寻路

2015-09-15 21:11 369 查看
使用数据结构 栈(Stack)来实现一种低级的迷宫寻路的功能。
低级是因为无法判断路径是不是最短的。

这里使用的栈结构如图 (这图我选择死亡...)



注意结构体里DataType的实际含义,是另外一个结构体,用于储存二维位置x,y

地图使用一个10x10的二维数组来表示,数字1表示该点是墙壁,0表示可以行走,2表示已经走过的地方。

我们用栈来储存走过的位置,比如我们从起点(4,0)出发,就把(4,0)压入栈,并把该点数值改为2,意为已经来过了。
如果遇到死路,那就不停地出栈,直到栈顶的这个点周围有路可走为止。

逻辑部分伪代码如下

while(没有到达终点)
{
  if(上下左右四个方向有路可走)
  {
    将可以走的那个位置(不是当前位置!)压入栈
  }
  else
  {
    出栈
  }
}

#include <stack>
#include <iostream>

using std::cout;
using std::endl;
using std::stack;

const int MAZEWIDTH = 10;
const int MAZEHEIGHT = 10;

//0可走
//1墙
//2走过
//3走过又退回来了
int Maze[MAZEWIDTH][MAZEHEIGHT] = {
//0  1  2  3  4  5  6  7  8  9
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,//0
1, 0, 1, 0, 0, 0, 1, 0, 0, 0,//1
1, 0, 0, 0, 1, 0, 1, 0, 0, 1,//2
1, 0, 1, 1, 0, 0, 1, 1, 0, 1,//3
1, 0, 1, 0, 0, 1, 0, 1, 0, 1,//4
0, 0, 1, 1, 0, 1, 0, 0, 0, 1,//5
1, 1, 0, 0, 0, 0, 1, 0, 1, 1,//6
1, 0, 1, 1, 1, 0, 1, 0, 0, 1,//7
1, 0, 0, 0, 0, 0, 0, 0, 0, 1,//8
1, 1, 1, 1, 1, 1, 1, 1, 1, 1//9
};

struct _XY {
int x, y;

_XY() {
x = y = 0;
}

_XY(int a, int b) : x(a), y(b) { }

int operator==(const struct _XY &a) {
return (a.x == x) && (a.y == y);
}
};

typedef _XY XY;

class MazeBreaker {
private:
int MazeMap[MAZEWIDTH][MAZEHEIGHT];
stack<XY> path;
XY start, end;

void push(XY xy) {
path.push(xy);
MazeMap[xy.x][xy.y] = 2;
}

void push(int x, int y) {
path.push(XY(x, y));
MazeMap[x][y] = 2;
}

void pop() {
if (!(path.top() == start)) {
XY &loc = path.top();
MazeMap[loc.x][loc.y] = 3;
path.pop();
}
}

int End() {
return path.top() == end;
}

void ThereIsAWay() {
XY &loc = path.top();
//UP
if (MazeMap[loc.x - 1][loc.y] == 0) {
push(loc.x - 1, loc.y);
return;
}
//RIGHT
if (MazeMap[loc.x][loc.y - 1] == 0) {
push(loc.x, loc.y - 1);
return;
}
//DOWN
if (MazeMap[loc.x + 1][loc.y] == 0) {
push(loc.x + 1, loc.y);
return;
}
//LEFT
if (MazeMap[loc.x][loc.y + 1] == 0) {
push(loc.x, loc.y + 1);
return;
}
pop();
return;
}

public:

void GenerateMap() {
for (int lop = 0; lop < MAZEWIDTH; lop++) {
for (int lop2 = 0; lop2 < MAZEHEIGHT; lop2++) {
MazeMap[lop][lop2] = Maze[lop][lop2];
}
}
push(start);
}

MazeBreaker() {
start.x = 5;
start.y = 0;
end.x = 1;
end.y = 9;
}

void FindPath() {
while (!End()) {
ThereIsAWay();
}

for (int lop = 0; lop < MAZEWIDTH; lop++) {
for (int lop2 = 0; lop2 < MAZEHEIGHT; lop2++) {
if (MazeMap[lop][lop2] == 2) {
cout << "O";
} else if (MazeMap[lop][lop2] == 3) {
cout << "X";
} else {
cout << " ";
}
}
cout << endl;
}
}

};

int main() {
MazeBreaker mb;
mb.GenerateMap();
mb.FindPath();
return 0;
}


[b]///////////以下是老版本////////////[/b]

首先是栈的头文件,注意栈结构体内容的具体定义

Stack.h

#ifndef _STACK_H_
#define _STACK_H_

#include<stdio.h>
#include<stdlib.h>

//以下两个数据大小视实际情况而定
//初始栈容量
#define STACK_INIT_SIZE 20
//每次扩容的增量
#define STACKINCREMENT 10

//迷宫地图
int Maze[10][10];

//表示位置
struct xy
{
int x, y;
};
typedef struct xy XY;
typedef  XY DataType;

struct stack
{
//指向栈最顶上的元素的接下来一个位置
//表示新入栈的值可以放在指向的地方
DataType *Top;
//指向栈底部,最里面的元素
DataType *Bottom;
//表示了当前栈的容量
int stacksize;
};
typedef struct stack STACK;

//新建栈
int InitStack(STACK *S);

//销毁栈
int DestroyStack(STACK *S);

//返回顶层元素
int GetTop(STACK S,int *x,int *y);

//Push操作,入栈,压栈
int Push(STACK *S, int x,int y);

//Pop操作,出栈
int Pop(STACK *S);

#endif


然后是定义

Stack.c

#include"Stack.h"

int InitStack(STACK *S)
{
//创建出设定长度的顺序表,地址赋给bottom指针
S->Bottom = (DataType*)malloc(STACK_INIT_SIZE*sizeof(DataType));
if (!S->Bottom)
{
return 0;
}
S->stacksize = STACK_INIT_SIZE;
S->Top = S->Bottom;
return 1;
}

int DestroyStack(STACK *S)
{
S->Top = NULL;
free(S->Bottom);
S->Bottom = NULL;
return 1;
}

int GetTop(STACK S, int *x, int *y)
{
if (S.Bottom != S.Top)
{
//由于top指向的是最顶上元素的下一个位置
//所以取出最顶上元素的时候
//要把top减去1
*x = ((S.Top - 1)->x);
*y = ((S.Top - 1)->y);
return 1;
}
return 0;
}

int Push(STACK *S, int x,int y)
{
//当超出当前栈的容量时
//这里应该只有等于的情况
//而不会大于
if ((S->Top - S->Bottom) >= S->stacksize)
{
//realloc函数将开辟指定的储存空间
//并将原来的数据全部移到这个新的储存空间
S->Bottom = (DataType*)realloc(S->Bottom, (S->stacksize + STACKINCREMENT)*sizeof(DataType));
if (!S->Bottom)
{
return 0;
}
//由于重新开辟了空间
//需要重新根据bottom指针的位置指定top
S->Top = S->Bottom + S->stacksize;
//最后增加当前栈容量
S->stacksize += STACKINCREMENT;
}
//再把入栈的数据存放好
(S->Top)->x = x;
(S->Top)->y = y;
S->Top++;

//在地图上将该点标为2
Maze[x][y] = 2;
return 1;
}

//将该点丢弃
int Pop(STACK *S)
{
if (S->Bottom == S->Top)
{
printf("Empty Stack!Can not pop!\n");
return 0;
}
//top指针先减1再取值
--S->Top;
return 1;
}


寻路的逻辑放在了main函数里,迷宫地图的定义也在这里

main.c

二维数组Maze存放了迷宫的信息,你也可以自己改改*。

#include"Stack.h"

#define Up 1
#define Right 2
#define Down 3
#define Left 4
//代表已无路可走
//End of Road
#define EOR 5

//迷宫的地图
//墙壁表示为1,可走的地方表示为0,走过的地方表示为2
//入口为(4,0),出口为(0,8)
//可自行更改,但请确保有通路

Maze[10][10] = {
//0,1,2,3,4,5,6,7,8,9
1,1,1,1,1,1,1,1,0,1,     //0
1,0,0,0,0,0,0,1,0,1,     //1
1,0,1,0,1,1,1,1,0,1,     //2
1,0,1,0,1,0,0,0,0,1,     //3
0,0,1,0,1,0,1,0,1,1,     //4
1,0,1,0,1,0,1,0,1,1,     //5
1,1,0,0,1,0,1,0,1,1,     //6
1,0,0,1,1,0,1,0,1,1,     //7
1,0,0,0,0,0,1,0,0,1,     //8
1,1,1,1,1,1,1,1,1,1 };  //9

//打印结果
int Print()
{
int lop, lop2;
for (lop = 0; lop < 10; lop++)
{
for (lop2 = 0; lop2 < 10; lop2++)
{
if (Maze[lop][lop2] == 2)
{
printf("1");
}
else
{
printf(" ");
}
}
printf("\n");
}
return 1;
}

int GameOver(STACK s, XY *loc,XY End)
{
GetTop(s, &(loc->x), &(loc->y));
if (loc->x == End.x && loc->y == End.y)
{
return 1;
}
else
{
return 0;
}
}

//1 up.2 right.3 down.4 left
//看看当前位置的上下左右还有没有能走的地方
int SearchPath(STACK s, XY loc)
{
int x, y;
x = loc.x;
y = loc.y;

//Up Available?
if (x != 0)
{
if (!Maze[x - 1][y])
{
return Up;
}
}
//Right ?
if (y != 9)
{
if (!Maze[x][y + 1])
{
return Right;
}
}
//Down?
if (x != 9)
{
if (!Maze[x + 1][y])
{
return Down;
}
}
//Left?
if (y != 0)
{
if (!Maze[x][y - 1])
{
return Left;
}
}
return EOR;
}

int main()
{
//储存走出迷宫的路径
STACK Path;
//储存当前位置
XY loc;
//起点终点的位置
XY Start = { 4,0 }, End = { 0,8 };

InitStack(&Path);
//将起点入栈
Push(&Path, Start.x, Start.y);

//开始
while (!GameOver(Path, &loc, End))
{
switch (SearchPath(Path, loc))
{
case Up:
Push(&Path, loc.x - 1, loc.y);
break;
case Right:
Push(&Path, loc.x, loc.y + 1);
break;
case Down:
Push(&Path, loc.x + 1, loc.y);
break;
case Left:
Push(&Path, loc.x, loc.y - 1);
break;
case EOR:
Pop(&Path);
break;
default:
printf("Shit Happened! Check your code!\n");
break;
}
}
Print();
DestroyStack(&Path);
return 0;
}


最后运行结果如图



有一行多出来的1,因为打印的是走过的路径。

*如果你想自己更改迷宫地图的话,请务必记得更改相应的起点和终点(114行)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: