导入:所谓迷宫问题,就是把迷宫看做一个二维数组(二维坐标系),在数组中寻找从一个点到另一个点的通路。利用“栈”的特点——只允许在顶端进行插入和删除——可以十分轻松的解决这一个问题。(结尾附完整代码)
一.创建“栈”,并实现有关“栈”的基本操作函数。
1.“栈”的数据结构定义:
typedef int DataType; //定义int为当前栈内存储的数据类型(后续会更改)
typedef struct
{
int MAXNUM; //记录当前栈的最大数据
int top; //记录栈顶的位置
DataType *element; //数据数组,可自定义数组长度
} seqStack;
typedef seqStack* PseqStack; //定义栈的指针形式
上面的代码中把int定义为DataType为了方便后续更改代码
2.“栈”的创建函数:
PseqStack CreateStack(int maxnum)
{
if (maxnum > 0)
{
PseqStack stack = (PseqStack)malloc(sizeof(PseqStack)); //为栈申请空间
stack->MAXNUM = maxnum;
stack->top = -1; //其实把栈顶标记为-1,表示栈为空
stack->element = (DataType *)malloc(sizeof(DataType) * maxnum); //为栈储存的数据申请空间
return stack;
}
else
{
printf( "maxnum不得小于0" ) ;
return NULL;
}
}
创建栈的时候,只需像下面这样调用函数即可:
int main()
{
PseqStack stack = PseqStack Stack = CreateStack(10);//参数为你想申请的最大数组容量
}
3.判断“栈”是否为空,是否为满,是否存在:
判断是否为空
/*
* 若栈不存在,则返回-1;若栈为空,则返回1;若栈不为空,则返回0。
*/
int IsEmptyStack(PseqStack Stack)
{
PseqStack stack = Stack;
if (stack == NULL)
{
return -1;
}
else
{
if (stack->top == -1) //若栈顶为-1则表明栈中已经空了
{
return 1;
}
else
{
return 0;
}
}
}
判断是否已满
/*
* 若栈不存在,则返回-1;若栈不满,则返回0;若栈满,则返回1。
*/
int IsFullStack(PseqStack Stack)
{
PseqStack stack = Stack;
if (stack == NULL)
{
return -1;
}
else
{
if (stack->top == stack->MAXNUM - 1) //栈顶的位置从0开始计数,计到MAXNUM-1时表示已满
{
return 1;
}
else
{
return 0;
}
}
}
4.实现“入栈”与“出栈”功能的函数:
入栈:
/*
* 将数据data插入栈中,若栈为空则返回-1;若栈已满则返回0;若插入成功则返回1。
*/
int PushStack(PseqStack Stack, DataType data)
{
PseqStack stack = Stack;
if (stack == NULL)
{
printf( "栈不存在\n" ) ;
return -1;
}
{
if (IsFullStack(stack) == 1)
{
printf( "栈已满,无法入栈\n" ) ;
return 0;
}
else
{
stack->top++;
stack->element[stack->top] = data;
return 1;
}
}
}
由于top是标记栈顶位置,所以每次入栈的操作都是先更新栈顶位置,再输入栈顶数据。
出栈:
/*
*弹出栈顶元素,若栈不存在则返回-1;若栈为空则返回0;若弹出成功则返回栈顶元素。
*/
DataType PopStack(PseqStack Stack)
{
PseqStack stack = Stack;
if (stack == NULL)
{
printf("栈不存在\n");
return -1;
}
else
{
if (IsEmptyStack(stack) == 1)
{
printf("栈为空,无法出栈\n");
return 0;
}
else
{
DataType data = stack->element[stack->top];
stack->element[stack->top] = 0;
stack->top--;
return data;
}
}
}
5.返回“栈”顶数据:
/*
*返回栈顶元素,若栈不存在则返回-1;若栈为空则返回0。
*/
DataType TopStack(PseqStack Stack)
{
PseqStack stack = Stack;
if (stack == NULL)
{
printf("栈不存在\n");
return -1;
}
else
{
if (IsEmptyStack(stack) == 1)
{
printf("栈为空\n");
return 0;
}
else
{
return stack->element[stack->top];
}
}
}
6.打印“栈”内数据:
将“栈”内数据全部打印出来,方便观察结果。
/*
*打印栈内现有元素,若栈不存在则返回-1;若栈为空则返回0。
*/
int PrintStack(PseqStack Stack)
{
PseqStack stack = Stack;
if (stack == NULL)
{
printf("栈不存在\n");
return -1;
}
else
{
if (IsEmptyStack(stack) == 1)
{
printf("栈为空\n");
return 0;
}
else
{
for (int i = 0; i <= stack->top; i++)
{
DataType data = stack->element[i];
printf("element[%d]:%d\n", i, data);
}
}
}
}
至此,有关“栈”的基本操作就已经全部完成,让我们正式进入解决“迷宫问题”的环节。
二.迷宫问题的算法思路讲解与代码实现:
1.初步认识迷宫问题:
1.认识地图:
首先,我们来看一下现有的迷宫地图
const int maze[12][12] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1,
1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1,
1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1,
1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1,
1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1,
1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1,
1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1,
1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1,
1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
迷宫的起始点为(1,1),终点为(10,10)。被标记为“1”的点表示是不可通行的“墙”,而标记为“0”的点则表示是可以通行的“路”。这种网格地图的标记权值在RPG游戏中经常会用到,比如我们熟知的《口袋妖怪》便是这样:
(口袋妖怪的地图中,用“1”标记不可通行的道路,用“c”标记可通行道路,用“4”标记水路等等)
2.流程图分析:
2.根据迷宫特性修改“栈”
1.定义结构体point,里面含有两个int型数据x,y;用于记录二维坐标。
typedef struct
{
int x; //坐标点的x值
int y; //坐标点的y值
} point;
2.在“栈”中储存point类型数据,用于记录走过的路径。
typedef point DataType; //将point数据类型定义为DataType
typedef struct
{
int MAXNUM;
int top;
DataType *element;
} seqStack;
typedef seqStack *PseqStack;
3.定义结构体direct用于表示在迷宫中的移动方向。
typedef struct
{
int incX; //increase_x表示x方向的增量
int incY; //increase_y表示y方向的增量
} Direct;
3.使用“栈”解决迷宫问题
上源码
int main()
{
int maze[12][12] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1,
1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1,
1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1,
1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1,
1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1,
1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1,
1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1,
1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1,
1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
PseqStack Stack = CreateStack(100);
int towards;
Direct direct;
DataType pos;
pos.x = 1;
pos.y = 1;
PushStack(Stack, pos); //起始点(1,1)
while (1)
{
for (towards = 0; towards < 4; towards++) //遍历上下左右四个方向,查询各点状态是否为出路
{
switch (towards)
{
case 0:
direct.incX = 1; //向右,沿X轴正方向移动
direct.incY = 0;
break;
case 1:
direct.incX = 0; //向下,沿Y轴正方向移动
direct.incY = 1;
break;
case 2:
direct.incX = -1; //向右,沿X轴负方向移动
direct.incY = 0;
break;
case 3:
direct.incX = 0; //向上,沿Y轴负方向移动
direct.incY = -1;
break;
default:
break;
}
if (maze[pos.x + direct.incX][pos.y + direct.incY] == 0) //若当前方向找到出路,则停止遍历
{
break;
}
}
if (maze[pos.x + direct.incX][pos.y + direct.incY] == 0) //若可以找到出路,则入栈新位置,并将旧位置点标记为-1
{
pos.x = pos.x + direct.incX;
pos.y = pos.y + direct.incY;
PushStack(Stack, pos);
maze[pos.x][pos.y] = -1;
}
else //若无法找到出路,则进行退栈操作(即返回上一步)
{
PopStack(Stack);
pos = TopStack(Stack);
continue;
}
if (IsEmptyStack(Stack) == 1) //若退栈回溯至起点,则表明该迷宫无解
{
printf("Cannot find the path!\n");
PrintStack(Stack);
break;
}
else //若当前位置已经到达(10,10),则表明找到出口,结束
{
if (TopStack(Stack).x == 10 && TopStack(Stack).y == 10)
{
break;
}
}
}
PrintStack(Stack); //打印当前栈内数据
return 0 ;
}
运行结果:
Point[0]=[1,1]
Point[1]=[2,1]
Point[2]=[2,2]
Point[3]=[2,3]
Point[4]=[3,3]
Point[5]=[4,3]
Point[6]=[5,3]
Point[7]=[5,4]
Point[8]=[6,4]
Point[9]=[7,4]
Point[10]=[8,4]
Point[11]=[8,5]
Point[12]=[8,6]
Point[13]=[7,6]
Point[14]=[6,6]
Point[15]=[5,6]
Point[16]=[4,6]
Point[17]=[3,6]
Point[18]=[3,7]
Point[19]=[2,7]
Point[20]=[1,7]
Point[21]=[1,8]
Point[22]=[1,9]
Point[23]=[2,9]
Point[24]=[3,9]
Point[25]=[4,9]
Point[26]=[5,9]
Point[27]=[6,9]
Point[28]=[6,8]
Point[29]=[7,8]
Point[30]=[8,8]
Point[31]=[9,8]
Point[32]=[9,9]
Point[33]=[10,9]
Point[34]=[10,10]
路线如下
三.总结
额其实也没什么好总结的,迷宫问题是很经典的数据结构问题,解法也有很多,相信大家都可以通过学习找出更优质的解法,欢迎一起讨论,如有不足也欢迎指出。
#include <stdio.h>
#include <stdlib.h>
/*
使用栈作为辅助结构,实现迷宫找路问题。
*/
typedef struct
{
int x;
int y;
} point;
typedef point DataType;
typedef struct
{
int MAXNUM;
int top;
DataType *element;
} seqStack;
typedef seqStack *PseqStack;
typedef struct
{
int incX;
int incY;
} Direct;
PseqStack CreateStack(int maxnum)
{
if (maxnum > 0)
{
PseqStack stack = (PseqStack)malloc(sizeof(PseqStack));
stack->MAXNUM = maxnum;
stack->top = -1;
stack->element = (DataType *)malloc(sizeof(DataType) * maxnum);
return stack;
}
else
{
return NULL;
}
}
/*
* 若栈不存在,则返回-1;若栈为空,则返回1;若栈不为空,则返回0。
*/
int IsEmptyStack(PseqStack Stack)
{
PseqStack stack = Stack;
if (stack == NULL)
{
return -1;
}
else
{
if (stack->top == -1)
{
return 1;
}
else
{
return 0;
}
}
}
/*
* 若栈不存在,则返回-1;若栈不满,则返回0;若栈满,则返回1。
*/
int IsFullStack(PseqStack Stack)
{
PseqStack stack = Stack;
if (stack == NULL)
{
return -1;
}
else
{
if (stack->top == stack->MAXNUM - 1)
{
return 1;
}
else
{
return 0;
}
}
}
/*
* 将数据data插入栈中,若栈为空则返回-1;若栈已满则返回0;若插入成功则返回1。
*/
int PushStack(PseqStack Stack, DataType data)
{
PseqStack stack = Stack;
if (stack == NULL)
{
printf("栈不存在");
return -1;
}
{
if (IsFullStack(stack) == 1)
{
printf("栈已满,无法入栈");
return 0;
}
else
{
stack->top++;
stack->element[stack->top] = data;
return 1;
}
}
}
/*
*弹出栈顶元素,若栈不存在则返回-1;若栈为空则返回0;若弹出成功则返回栈顶元素。
*/
DataType PopStack(PseqStack Stack)
{
PseqStack stack = Stack;
DataType rData;
rData.x = -1;
rData.y = -1;
if (stack == NULL)
{
printf("栈不存在");
return rData;
}
else
{
if (IsEmptyStack(stack) == 1)
{
printf("栈为空,无法出栈");
return rData;
}
else
{
DataType data = stack->element[stack->top];
rData.x = 0;
rData.y = 0;
stack->element[stack->top] = rData;
stack->top--;
return data;
}
}
}
/*
*返回栈顶元素,若栈不存在则返回-1;若栈为空则返回0。
*/
DataType TopStack(PseqStack Stack)
{
PseqStack stack = Stack;
DataType rData;
rData.x = -1;
rData.y = -1;
if (stack == NULL)
{
return rData;
}
else
{
if (IsEmptyStack(stack))
{
return rData;
}
else
{
return stack->element[stack->top];
}
}
}
/*
*打印栈内现有元素,若栈不存在则返回-1;若栈为空则返回0。
*/
int PrintStack(PseqStack Stack)
{
PseqStack stack = Stack;
if (stack == NULL)
{
return -1;
}
else
{
if (IsEmptyStack(stack) == 1)
{
return 0;
}
else
{
for (int i = 0; i <= stack->top; i++)
{
DataType data = stack->element[i];
printf("Point[%d]=[%d,%d]\n", i, data.x, data.y);
}
}
}
}
/*
* 使用栈作为辅助结构,实现迷宫找路问题。
* 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
* element元素十位数表示x,个位数表示y
*/
void TASK_3(void)
{
int maze[12][12] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1,
1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1,
1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1,
1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1,
1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1,
1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1,
1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1,
1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1,
1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
PseqStack Stack = CreateStack(100);
int towards;
Direct direct;
DataType pos;
pos.x = 1;
pos.y = 1;
PushStack(Stack, pos); //起始点(1,1)
while (1)
{
for (towards = 0; towards < 4; towards++) //遍历上下左右四个方向,查询各点状态是否为出路
{
switch (towards)
{
case 0:
direct.incX = 1; //向右,沿X轴正方向移动
direct.incY = 0;
break;
case 1:
direct.incX = 0; //向下,沿Y轴正方向移动
direct.incY = 1;
break;
case 2:
direct.incX = -1; //向右,沿X轴负方向移动
direct.incY = 0;
break;
case 3:
direct.incX = 0; //向上,沿Y轴负方向移动
direct.incY = -1;
break;
default:
break;
}
if (maze[pos.x + direct.incX][pos.y + direct.incY] == 0) //若当前方向找到出路,则停止遍历
{
break;
}
}
if (maze[pos.x + direct.incX][pos.y + direct.incY] == 0) //若可以找到出路,则入栈新位置,并将旧位置点标记为-1
{
pos.x = pos.x + direct.incX;
pos.y = pos.y + direct.incY;
PushStack(Stack, pos);
maze[pos.x][pos.y] = -1;
}
else //若无法找到出路,则进行退栈操作(即返回上一步)
{
PopStack(Stack);
pos = TopStack(Stack);
continue;
}
if (IsEmptyStack(Stack) == 1) //若退栈回溯至起点,则表明该迷宫无解
{
printf("Cannot find the path!\n");
PrintStack(Stack);
break;
}
else //若当前位置已经到达(10,10),则表明找到出口,结束
{
if (TopStack(Stack).x == 10 && TopStack(Stack).y == 10)
{
break;
}
}
}
PrintStack(Stack); //打印当前栈内数据
}
int main()
{
TASK_3();
return 0;
}