迷宫求解

基于栈实现迷宫求解问题

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;
}

结果演示







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值