基于栈实现迷宫求解问题
seqstack.h
#define _CRT_SECURE_NO_WARNINGS 1
//先进后出
#pragma once
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
#define FOR_MAZE
#ifdef FOR_MAZE
typedef struct Point
{
int row;
int col;
}Point;
typedef Point SeqStackType;
#else
typedef char SeqStackType;
#endif
typedef struct SeqStack
{
SeqStackType data[MAXSIZE];
size_t size;
} SeqStack;
void SeqStackInit(SeqStack* stack)
{
if (stack == NULL)
return;
stack->size = 0;
}
void SeqStackDestroy(SeqStack* stack)
{
if (stack == NULL)
return;
stack->size = 0;
}
void SeqStackPush(SeqStack* stack, SeqStackType value)
{
if (stack == NULL)
return;
if (stack->size >= MAXSIZE)
return;
stack->data[stack->size++] = value;
}
void SeqStackPop(SeqStack* stack)
{
if (stack == NULL)
return;
if (stack->size == 0)
return;
--stack->size;
}
int SeqStackTop(SeqStack* stack, SeqStackType* value)
{
if (stack == NULL || value == NULL)
return 0;
if (stack->size == 0)
return 0;
*value = stack->data[stack->size - 1];
return 1;
}
size_t SeqStackSize(SeqStack* stack)
{
if (stack == NULL)
return (size_t)-1;
return stack->size;
}
void SeqStackAssgin(SeqStack* from, SeqStack* to)
{
if (from == NULL || to == NULL)
return;
to->size = from->size;
size_t i = 0;
for (; i < from->size; ++i)
to->data[i] = from->data[i];
//memcpy(to, from, sizeof(SeqStack));
}
//只可以在迷宫中使用
void SeqStackDebugPrint(SeqStack* stack, const char* msg)
{
printf("%s\n", msg);
if (stack == NULL)
{
printf("stack==NULL\n");
return;
}
printf("[栈底] ");
size_t i = 0;
for (; i < stack->size; ++i)
printf("[%d,%d] ", stack->data[i].row, stack->data[i].col);
printf("[栈顶]\n\n");
}
maze.c
#include "seqstack.h"
#define MAZE_ROW 6
#define MAZE_COL 6
typedef struct Maze
{
int map[MAZE_ROW][MAZE_COL];
}Maze;
int CanStay(Maze* maze, Point cur)
{
if (cur.row < 0 || cur.row >= MAZE_ROW || cur.col < 0 || cur.col >= MAZE_COL)
return 0;
if (maze->map[cur.row][cur.col] == 1)
return 1;
return 0;
}
void Mark(Maze* maze, Point cur)
{
maze->map[cur.row][cur.col] = 2;
}
int IsExit(Point cur, Point entry)
{
if (cur.row == 0 || cur.row == MAZE_ROW - 1 || cur.col == 0 || cur.col == MAZE_COL - 1)
{
if (cur.row == entry.row && cur.col == entry.col)
return 0;
return 1;
}
return 0;
}
void _HasPath(Maze* maze, Point cur, Point entry)
{
//1.判断当前点是否可以落脚(点在地图上,此位置的值为1)
if (!CanStay(maze, cur))
return;
//2.标记当前点为走过的点(标记此位置的值为2)
Mark(maze, cur);
//3.判断当前点是否是出口点(点在边缘上,不是入口点)
if (IsExit(cur, entry))
{
printf("找到了一条路径!\n");
return;
}
//4.按照顺时针方向探测周围的邻接点(递归调用_HasPath())
Point up = cur;
up.row -= 1;
_HasPath(maze, up, entry);
Point right = cur;
right.col += 1;
_HasPath(maze, right, entry);
Point down = cur;
down.row += 1;
_HasPath(maze, down, entry);
Point left = cur;
left.col -= 1;
_HasPath(maze, left, entry);
//5.如果四个地方都探测过了,就直接返回
return;
}
//递归查找迷宫上是否存在路径
void HasPath(Maze* maze, Point entry)
{
if (maze == NULL)
return;
_HasPath(maze, entry, entry);
}
//循环查找迷宫上是否存在路径
void HasPathByLoop(Maze* maze, Point entry)
{
if (maze == NULL)
return;
//1.判断入口点是否可以落脚
if (!CanStay(maze, entry))
return;
//2.标记入口点为走过的点,将入口点入栈
Mark(maze, entry);
SeqStack stack;
SeqStackInit(&stack);
SeqStackPush(&stack, entry);
Point cur = entry;
//3.进入循环,取栈顶元素为当前点
while (SeqStackTop(&stack, &cur))
{
//4.判断当前点是否是出口点
if (IsExit(cur, entry))
{
printf("找到了一条路径!\n");
return;
}
//5.按照顺时针方向探测周围的邻接点是否可以落脚
Point up = cur;
up.row -= 1;
//6.若某个邻接点可以落脚,标记这个邻接点,并将此邻接点入栈,进入下一次循环
if (CanStay(maze, up))
{
Mark(maze, up);
SeqStackPush(&stack, up);
continue;
}
Point right = cur;
right.col += 1;
if (CanStay(maze, right))
{
Mark(maze, right);
SeqStackPush(&stack, right);
continue;
}
Point down = cur;
down.row += 1;
if (CanStay(maze, down))
{
Mark(maze, down);
SeqStackPush(&stack, down);
continue;
}
Point left = cur;
left.col -= 1;
if (CanStay(maze, left))
{
Mark(maze, left);
SeqStackPush(&stack, left);
continue;
}
//7.若四个方向都探测完毕,将当前点出栈
SeqStackPop(&stack);
}
return;
}
void _GetShortPath(Maze* maze, Point cur, Point entry, SeqStack* cur_path, SeqStack* short_path)
{
//1.判断当前点是否可以落脚
if (!CanStay(maze, cur))
return;
//2.若可以落脚,标记当前点,并将当前点push到cur_path
Mark(maze, cur);
SeqStackPush(cur_path, cur);
//3.判断当前点是否是出口,若是出口
if (IsExit(cur, entry))
{
SeqStackDebugPrint(cur_path, "找到了一条路径!");
//(1)比较cur_path和short_path的长度
//(2)若short_path为空或者cur_path比short_path小,则用cur_path替换short_path
if (SeqStackSize(short_path) == 0 || SeqStackSize(cur_path) < SeqStackSize(short_path))
{
SeqStackAssgin(cur_path, short_path);
SeqStackDebugPrint(short_path, "当前路径是一条较短的路径");
}
//(3)将cur_path出栈,返回到上一层栈桢
SeqStackPop(cur_path);
return;
}
//4.按照顺时针顺序,递归调用_GetShortPath()完成邻接点的判定
Point up = cur;
up.row -= 1;
_GetShortPath(maze, up, entry, cur_path, short_path);
Point right = cur;
right.col += 1;
_GetShortPath(maze, right, entry, cur_path, short_path);
Point down = cur;
down.row += 1;
_GetShortPath(maze, down, entry, cur_path, short_path);
Point left = cur;
left.col -= 1;
_GetShortPath(maze, left, entry, cur_path, short_path);
//5.若四个方向都探测完了,回溯到上一个位置,先将cur_path出栈,再返回
SeqStackPop(cur_path);
return;
}
void GetShortPath(Maze* maze, Point entry)
{
SeqStack short_path;
SeqStack cur_path;
SeqStackInit(&short_path);
SeqStackInit(&cur_path);
_GetShortPath(maze, entry, entry, &cur_path, &short_path);
SeqStackDebugPrint(&short_path, "最短路径!");
}
int CanStayWithCycle(Maze* maze, Point cur, Point pre)
{
if (cur.row < 0 || cur.row >= MAZE_ROW || cur.col < 0 || cur.col >= MAZE_COL)
return 0;
if (maze->map[cur.row][cur.col] == 1)
return 1;
if (pre.row >= 0 && pre.row < MAZE_ROW && pre.col >= 0 && pre.col < MAZE_COL)
{
if (maze->map[cur.row][cur.col] - 1 > maze->map[pre.row][pre.col])
return 1;
}
return 0;
}
void MarkWithCycle(Maze* maze, Point cur, Point pre)
{
if (pre.row < 0 || pre.row >= MAZE_ROW || pre.col < 0 || pre.col >= MAZE_COL)
{
maze->map[cur.row][cur.col] = 2;
return;
}
maze->map[cur.row][cur.col] = maze->map[pre.row][pre.col] + 1;
return;
}
void _GetShortPathWithCycle(Maze* maze, Point cur, Point pre, Point entry, SeqStack* cur_path, SeqStack* short_path)
{
//1.判断当前点是否可以落脚
if (!CanStayWithCycle(maze, cur, pre))
return;
//2.若可以落脚,标记当前点,并将当前点push到cur_path
MarkWithCycle(maze, cur, pre);
SeqStackPush(cur_path, cur);
//3.判断当前点是否是出口,若是出口
if (IsExit(cur, entry))
{
SeqStackDebugPrint(cur_path, "找到了一条路径!");
//(1)比较cur_path和short_path的长度
//(2)若short_path为空或者cur_path比short_path小,则用cur_path替换short_path
if (SeqStackSize(short_path) == 0 || SeqStackSize(cur_path) < SeqStackSize(short_path))
{
SeqStackAssgin(cur_path, short_path);
SeqStackDebugPrint(short_path, "当前路径是一条较短的路径");
}
//(3)将cur_path出栈,返回到上一层栈桢
SeqStackPop(cur_path);
return;
}
//4.按照顺时针顺序,递归调用_GetShortPath()完成邻接点的判定
Point up = cur;
up.row -= 1;
_GetShortPathWithCycle(maze, up, cur, entry, cur_path, short_path);
Point right = cur;
right.col += 1;
_GetShortPathWithCycle(maze, right, cur, entry, cur_path, short_path);
Point down = cur;
down.row += 1;
_GetShortPathWithCycle(maze, down, cur, entry, cur_path, short_path);
Point left = cur;
left.col -= 1;
_GetShortPathWithCycle(maze, left, cur, entry, cur_path, short_path);
//5.若四个方向都探测完了,回溯到上一个位置,先将cur_path出栈,再返回
SeqStackPop(cur_path);
return;
}
void GetShortPathWithCycle(Maze* maze, Point entry)
{
SeqStack short_path;
SeqStack cur_path;
SeqStackInit(&short_path);
SeqStackInit(&cur_path);
Point pre = { -1, -1 };
_GetShortPathWithCycle(maze, entry, pre, entry, &cur_path, &short_path);
SeqStackDebugPrint(&short_path, "最短路径!");
}
//
//以下为测试代码//
//
#define TEST_HEADER printf("\n**********%s**********\n",__FUNCTION__)
//简单迷宫
void MazeInit(Maze* maze)
{
int map[MAZE_ROW][MAZE_COL] =
{
{0, 1, 0, 0, 0, 0},
{0, 1, 1, 1, 0, 0},
{0, 1, 0, 1, 1, 0},
{0, 1, 1, 0, 0, 0},
{0, 0, 1, 0, 0, 0},
{0, 0, 1, 0, 0, 0}
};
size_t i = 0;
for (; i < MAZE_ROW; ++i)
{
size_t j = 0;
for (; j < MAZE_COL; ++j)
{
maze->map[i][j] = map[i][j];
}
}
}
//多出口迷宫
void MazeInitMultiExit(Maze* maze)
{
int map[MAZE_ROW][MAZE_COL] =
{
{0, 1, 0, 0, 0, 0},
{0, 1, 1, 1, 0, 0},
{0, 1, 0, 1, 1, 1},
{1, 1, 1, 0, 0, 0},
{0, 0, 1, 0, 0, 0},
{0, 0, 1, 0, 0, 0}
};
size_t i = 0;
for (; i < MAZE_ROW; ++i)
{
size_t j = 0;
for (; j < MAZE_COL; ++j)
{
maze->map[i][j] = map[i][j];
}
}
}
//多出口带环迷宫
void MazeInitMultiExitWithCycle(Maze* maze)
{
int map[MAZE_ROW][MAZE_COL] =
{
{0, 1, 0, 0, 0, 0},
{0, 1, 1, 1, 0, 0},
{0, 1, 0, 1, 1, 1},
{1, 1, 1, 1, 0, 0},
{0, 0, 1, 0, 0, 0},
{0, 0, 1, 0, 0, 0}
};
size_t i = 0;
for (; i < MAZE_ROW; ++i)
{
size_t j = 0;
for (; j < MAZE_COL; ++j)
{
maze->map[i][j] = map[i][j];
}
}
}
void MazePrint(Maze* maze)
{
size_t i = 0;
if (maze == NULL)
return;
for (; i < MAZE_ROW; ++i)
{
size_t j = 0;
for (; j < MAZE_COL; ++j)
{
printf("%d ", maze->map[i][j]);
}
printf("\n");
}
printf("\n");
}
void TestHasPath()
{
TEST_HEADER;
Maze maze;
MazeInit(&maze);
Point entry = { 0, 1 };
HasPath(&maze, entry);
MazePrint(&maze);
}
void TestHasPathByLoop()
{
TEST_HEADER;
Maze maze;
MazeInit(&maze);
Point entry = { 0, 1 };
HasPathByLoop(&maze, entry);
MazePrint(&maze);
}
void TestGetShortPath()
{
TEST_HEADER;
Maze maze;
MazeInitMultiExit(&maze);
Point entry = { 0, 1 };
GetShortPath(&maze, entry);
MazePrint(&maze);
}
void TestGetShortPathWithCycle()
{
TEST_HEADER;
Maze maze;
MazeInitMultiExitWithCycle(&maze);
Point entry = { 0, 1 };
GetShortPathWithCycle(&maze, entry);
MazePrint(&maze);
}
int main()
{
TestHasPath();
TestHasPathByLoop();
TestGetShortPath();
TestGetShortPathWithCycle();
system("pause");
return 0;
}
结果演示