利用栈求解迷宫 --数据结构实验

一、实验目的

1、了解回溯法在求解迷宫问题中的应用

2、进一步掌握栈的使用

二、实验内容

用回溯法求解迷宫问题,可以用一个栈保存探索的序列。并且在该迷宫的行走中,站在一点可以有八个方向选择。

比如如下的迷宫

Enter-> 0   1   1   1   0   0   0   0   0   0

0   0   0   1   0   0   0   1   0   0

0   1   0   1   1   0   0   1   0   0

0   1   0   0   1   0   1   1   0   0

0   1   0   0   1   0   1   1   0   0

1   1   1   0   1   0   1   0   0   0

0   0   1   0   0   0   1   0   1   1

0   0   1   0   0   0   1   0   1   1

0   1   1   0   1   0   1   0   0   0

0   0   0   0   1   0   1   1   0   0 --> EXIT

下面是可能的路径(注意:从入口到出口可能有多条路径,优先选择的方向不同,路径可能也不一样!)

 Path: ( maze[0][0], maze[1][0], maze[1][1], maze[1][2], maze[2][2],

   maze[3][2], maze[3][3], maze[4][3], maze[5][3], maze[6][3],

   maze[6][4], maze[6][5], maze[5][5], maze[4][5], maze[3][5],

   maze[2][5], maze[2][6], maze[1][6], maze[0][6], maze[0][7],

   maze[0][8], maze[1][8], maze[2][8], maze[3][8], maze[4][8],

   maze[5][8], maze[5][7], maze[6][7], maze[7][7], maze[8][7],

   maze[8][8], maze[8][9], maze[9][9])

 

Enter-> X   1   1   1   0   0   X---X---X   0

X---X---X   1   0   0   X   1   X   0

0   1   X   1   1   X---X   1   X   0

0   1   X---X   1   X   1   1   X   0

0   1   0   X   1   X   1   1   X   0

1   1   1   X   1   X   1   X---X   0

0   0   1   X---X---X   1   X   1   1

0   0   1   0   0   0   1   X   1   1

0   1   1   0   1   0   1   X-- X-- X

0   0   0   0   1   0   1   1   0   X --> EXIT

 

1、提示:

1)数据结构:

² 用二维数组MAZE[m+2][n+2]表示迷宫的结构,数组中的值为1表示是墙,为0表示可以走通。(用MAZE[m+2][n+2]而不用MAZE[m][n]的原因在于想表示和编写代码的时候简单些,而且让迷宫周围都是墙,防止错误的走出去)

² 用二维数组MARK[m+2][n+2]表示迷宫是否被走过,主要是为了回溯时已经证明走不通的路线就不要再去走了。(用MARK[m+2][n+2]而不用MARK[m][n]的原因在于想表示和编写代码的时候简单些)

² 二维数据MOVE[8][2]是为了更方便的移动到下一步,改变坐标。这个二维数组是为了更好的转换坐标(八个方向,从07),而且也能避免重复走路

² 用栈保存走过的路径

2)输出:

² 迷宫布局,用0表示可以走通的地方,用1表示墙

² 如果能走通,则输出路径和路径的长度;若不能走通,则输出提示不能走通

² 带有路径的迷宫布局


思路:

定义一个二位数组,保存这些迷宫的节点,并且规定等于1的数组表示为墙,等于0的数组表示为通道,为了不让探索路线的时候,走出所定义的迷宫区域,我们建立一堵墙将除了出口为0外,别的都为1,即为墙。

利用栈求解迷宫 --数据结构实验_第1张图片


          迷宫建立好了,怎么探索路线呢?首先,每个节点都有8个方向可以探索,每个节点都有八个方向,



我们可以定义一个 num[][] 数组记录节点已探索几个方向,再定义一个数组 dir[][] 记录该节点下一次探索该往哪个方向探索。我们需要用回溯的方法,将每个方向都探索一边(每探索一个方向则 num[][] 加1,如果num[][]小于8则继续探索),如果除了进到这个节点的那个方向,另外7个方向都是墙壁,则原路返回。



利用栈求解迷宫 --数据结构实验_第2张图片

为了防止节点还没探索完方向就返回了(如每个节点探索方向的顺序都按照顺时针 0 ->1....->7)


如上图的就是还没有探索完就返回了。为了解决这个问题,我们让节点第一次探索的方向为进入本节点的方向的下一个方向。



代码:

// T2.cpp: 定义控制台应用程序的入口点。
/*2017年10月28日
BY:薛8
数据结构迷宫实验 */
#include "stdafx.h"
#include


int dir[12][12] = { 0 };   //dir是向
int num[12][12] = { 0 };   // num是已走的方向数
struct direction {   //方向结构体,含有x,y两个成员
int x;
int y;
};
typedef struct direction direction;
direction move[8];


struct stackNode {  //结构体 记录压入栈用的坐标
int x;
int y;
};
typedef struct stackNode stackNode;
struct stack {
stackNode qmaze[100] = { 0 };
int top;  //top是栈顶
};
typedef struct stack stack;
void defineDirection() {  //定义八个方向
move[0].x = 0; //第一个方向 向东走一步 
move[0].y = 1;
move[1].x = 1; //第二个方向 向东南方向走一步 (对角线)
move[1].y = 1;
move[2].x = 1;  //第三个方向 向南方向走一步 
move[2].y = 0;
move[3].x = 1; //第四个方向 向西南方向走一步  (对角线)
move[3].y = -1;
move[4].x = 0; //第五个方向 向西方向走一步 
move[4].y = -1;
move[5].x = -1; //第六个方向 向西北方向走一步 (对角线)
move[5].y = -1;
move[6].x = -1; //第七个方向 向北方向走一步 
move[6].y = 0;
move[7].x = -1; //第八个方向 向动北向走一步 (对角线)
move[7].y = 1;
}
void defineMaze(int maze[12][12]) {  //定义迷宫 数组中的值为1表示是墙,为0表示可以走通
//定义迷宫四周的墙壁 防止走出围墙外面
maze[0][0] = 1;   //第一个数组是行 第二个数组是竖
maze[1][0] = 2;   //2是入口 3是出口
maze[2][0] = 1;
maze[3][0] = 1;
maze[4][0] = 1;
maze[5][0] = 1;
maze[6][0] = 1;
maze[7][0] = 1;
maze[8][0] = 1;
maze[9][0] = 1;
maze[10][0] = 1;
maze[11][0] = 1;
maze[0][11] = 1;
maze[1][11] = 1;
maze[2][11] = 1;
maze[3][11] = 1;
maze[4][11] = 1;
maze[5][11] = 1;
maze[6][11] = 1;
maze[7][11] = 1;
maze[8][11] = 1;
maze[9][11] = 1;
maze[10][11] = 3; //出口
maze[11][11] = 1;


maze[0][1] = 1;
maze[0][2] = 1;
maze[0][3] = 1;
maze[0][4] = 1;
maze[0][5] = 1;
maze[0][6] = 1;
maze[0][7] = 1;
maze[0][8] = 1;
maze[0][9] = 1;
maze[0][10] = 1;


maze[11][1] = 1;
maze[11][2] = 1;
maze[11][3] = 1;
maze[11][4] = 1;
maze[11][5] = 1;
maze[11][6] = 1;
maze[11][7] = 1;
maze[11][8] = 1;
maze[11][9] = 1;
maze[11][10] = 1;


maze[1][1] = 0;
maze[1][2] = 1;
maze[1][3] = 1;
maze[1][4] = 1;
maze[1][5] = 0;
maze[1][6] = 0;
maze[1][7] = 0;
maze[1][8] = 0;
maze[1][9] = 0;
maze[1][10] = 0;


maze[2][1] = 0;
maze[2][2] = 0;
maze[2][3] = 0;
maze[2][4] = 1;
maze[2][5] = 0;
maze[2][6] = 0;
maze[2][7] = 0;
maze[2][8] = 1;
maze[2][9] = 0;
maze[2][10] = 0;


maze[3][1] = 0;
maze[3][2] = 1;
maze[3][3] = 0;
maze[3][4] = 1;
maze[3][5] = 1;
maze[3][6] = 0;
maze[3][7] = 0;
maze[3][8] = 1;
maze[3][9] = 0;
maze[3][10] = 0;


maze[4][1] = 0;
maze[4][2] = 1;
maze[4][3] = 0;
maze[4][4] = 0;
maze[4][5] = 1;
maze[4][6] = 0;
maze[4][7] = 1;
maze[4][8] = 1;
maze[4][9] = 0;
maze[4][10] = 0;


maze[5][1] = 0;
maze[5][2] = 1;
maze[5][3] = 0;
maze[5][4] = 0;
maze[5][5] = 1;
maze[5][6] = 0;
maze[5][7] = 1;
maze[5][8] = 1;
maze[5][9] = 0;
maze[5][10] = 0;


maze[6][1] = 1;
maze[6][2] = 1;
maze[6][3] = 1;
maze[6][4] = 0;
maze[6][5] = 1;
maze[6][6] = 0;
maze[6][7] = 1;
maze[6][8] = 0;
maze[6][9] = 0;
maze[6][10] = 0;


maze[7][1] = 0;
maze[7][2] = 0;
maze[7][3] = 1;
maze[7][4] = 0;
maze[7][5] = 0;
maze[7][6] = 0;
maze[7][7] = 1;
maze[7][8] = 0;
maze[7][9] = 1;
maze[7][10] = 1;


maze[8][1] = 0;
maze[8][2] = 0;
maze[8][3] = 1;
maze[8][4] = 0;
maze[8][5] = 0;
maze[8][6] = 0;
maze[8][7] = 1;
maze[8][8] = 0;
maze[8][9] = 1;
maze[8][10] = 1;


maze[9][1] = 0;
maze[9][2] = 1;
maze[9][3] = 1;
maze[9][4] = 0;
maze[9][5] = 1;
maze[9][6] = 0;
maze[9][7] = 1;
maze[9][8] = 0;
maze[9][9] = 0;
maze[9][10] = 0;


maze[10][1] = 0;
maze[10][2] = 0;
maze[10][3] = 0;
maze[10][4] = 0;
maze[10][5] = 1;
maze[10][6] = 0;
maze[10][7] = 1;
maze[10][8] = 1;
maze[10][9] = 0;
maze[10][10] = 0;
}
void stack_push(stack* qstack, int n, int x, int y) {  //压栈 n是栈数 x y是入栈节点的坐标
qstack->qmaze[n].x = x;
qstack->qmaze[n].y = y;
qstack->top = n;
}
void stack_pop(stack* qstack, int n) {  //退栈
qstack->top -= 1;
}
void mazePath(int maze[12][12]) {
int n = 0;
int j = 1, k = 1;
stack* qstack = (stack*)malloc(sizeof(stack));
stack_push(qstack, n, j, k);  //入口压入栈
while (maze[j][k] != 3) {   //j k 表示当前结点 a b表示上一个节点
int a = 1, b = 1;
int i;
i = dir[j][k];  //本节点上一次走的方向 + 1 继续探索
while (num[j][k] < 8) {
i = dir[j][k];  //本节点上一次走的方向 + 1 继续探索
while (1) {
i = dir[j][k];  //本节点上一次走的方向 + 1 继续探索
j = j + move[i].x;
k = k + move[i].y;
if (maze[j][k] == 0 && num[j][k] < 8) {
n++;
a = j - move[i].x;
b = k - move[i].y;
dir[j][k] = (i + 5) % 8;  //本节点可以走 则将本节点下一个探索方向为(i + 1) % 8
num[a][b] += 1;
//i = 0;
stack_push(qstack, n, j, k);
}
if (maze[j][k] == 1 || maze[j][k] == 2) {
a = j - move[i].x;
b = k - move[i].y;
j = j - move[i].x;
k = k - move[i].y;
dir[a][b] = (i + 1) % 8;  //本节点不可走 则将上一节点下一个探索方向为(i + 1) % 8;
num[a][b] += 1;
break;
}
if (maze[j][k] == 1 && num[j][k] == 8 || maze[j][k] == 0 && num[j][k] == 8) {
stack_pop(qstack, n);
a = j - move[i].x;
b = k - move[i].y;
j = j - move[i].x;
k = k - move[i].y;
dir[a][b] = (i + 1) % 8;  //本节点不可走 则将上一节点下一个探索方向为(i + 1) % 8;
num[a][b] += 1;
break;
}
if (maze[j][k] == 3) {  //找到出口 打印路线
n++;
stack_push(qstack, n, j, k);
printf_s("\n\n以下是迷宫路线(坐标)\n");
for (int p = 0; p <= qstack->top; p++) {
printf("(%d,%d)->", qstack->qmaze[p].x, qstack->qmaze[p].y);
int xx = qstack->qmaze[p].x;
int yy = qstack->qmaze[p].y;
maze[xx][yy] = 8 ;
}
printf_s("\n\n以下是迷宫路线(8表示所走过的坐标)\n");
printf("     ");
for (int i = 0; i <= 11; i++) {
for (int y = 0; y <= 11; y++) {
if (maze[i][y] == 1) {
printf_s("■ ");
}
else if (maze[i][y] == 0) {
printf_s("□ ");
}
else if (maze[i][y] != 2 && maze[i][y] != 3) {
switch (dir[i][y])   //根据各个点所正处在的方向数(dir[i][y]) 输出箭头
{
case 0:
printf_s("→ ");
break;
case 1:
printf_s("↘ ");
break;
case 2:
printf_s("↓ ");
break;
case 3:
printf_s("↙ ");
break;
case 4:
printf_s("← ");
break;
case 5:
printf_s("↖ ");
break;
case 6:
printf_s("↑ ");
break;
case 7:
printf_s("↗ ");
break;
default:
break;
}
}
}
if (i == 0) {
printf("\nInter-> ");
}
else if (i == 10) {
printf("--->Out\n     ");
}
else {
printf_s("\n     ");
}


}
break;
}
}
i++;
}
n++;
}


}
int main()
{
int maze[12][12];
defineMaze(maze);
defineDirection();
printf("     ");
for (int i = 0; i <= 11; i++) {
for (int y = 0; y <= 11; y++) {
if (maze[i][y] == 1) {
printf_s("■ ");
}
if (maze[i][y] == 0) {
printf_s("□ ");
}
}
if (i == 0) {
printf("\nInter-> ");
}
else if (i == 10) {
printf("--->Out\n     ");
}
else {
printf_s("\n     ");
}


}
mazePath(maze);
return 0;
}



运行截图:

利用栈求解迷宫 --数据结构实验_第3张图片

你可能感兴趣的:(c)