C语言——迷宫问题

一、题目分析

迷宫问题本质上本质上是对数组的一个遍历,向上下左右四个方向进行遍历。当上下左右四个方向都无法行动时,将路径进行回溯,找到另一个可以行动的方向,直到找到出口。
显然,在遍历的过程中会有很多的问题:
1、当向前运动时,对上下左右四个方向进行遍历就会找到走过的路径,所以需要对走过的路径进行一个标记。
2、也会出现数组越界的问题,需要对下标进行控制。
3、最后是路径存储的问题。如何将走过的路径进行保存,并且如果路不通的时候,如何将路径删除,保存新的路径。显然栈是一个很好的方式来保存路径。按照后进先出的原则,可以将路径倒退删除,进行回溯。
4、既然选择了栈来保存数据,那么打印的时候又会遇到新的问题。我们需要打印从开始到结束的路径,然而栈的特性是后进先出,打印时便会将路径倒过来打印。所以需要另一个栈,来将存储路径的数据倒一遍,再将新栈打印。
显然C语言对这个问题的实现是有些麻烦的,我们需要自己写一个栈出来,再解决剩下的问题。

二、代码分析

1、主函数
	int N = 0, M = 0;
	scanf("%d%d", &N, &M);
	int** maze=(int**)malloc(sizeof(int*) * N);//malloc一个二维数组
	for (int i = 0; i < N; i++)
	{
   
   
		maze[i] = (int*)malloc(sizeof(int) * M);
	}
	for (int i = 0; i < N; i++)//数据输入
	{
   
   
		for (int j = 0; j < M; j++)
			scanf("%d", &maze[i][j]);
	}

malloc一个二维数组maze,用来作为迷宫。0代表路可以走通,1代表无法走通。当然,malloc的空间要在使用完成后free掉,避免内存泄漏。

Stack path;//利用栈保存路径
typedef struct Pos//位置坐标
{
   
   
	int row;
	int col;
}Pos;

建立一个栈path来存储路径,以及一个坐标结构体来表示位置坐标。栈储存的数据类型即为定义的struct Pos。将栈进行初始化,将坐标设为入口坐标{0,0}。在这里将path定义为了全局变量,方便函数的使用。

	StackInit(&path);//初始化栈
	Pos cur = {
   
    0,0 };//入口位置坐标
	if (GetMazePath(maze, N, M, cur))//判断是否能走到出口
	{
   
   
		PrintPath();//打印路径
	}
	else
	{
   
   
		printf("no path\n");
	}

	StackDestory(&path);//销毁栈
	for (int i = 0; i < N; i++)
		free(maze[i]);
	free(maze);//释放二维数组
	return 0;

GetMazePath函数是用来判断是否能找到路径,将迷宫maze,行N,列M,入口坐标cur传入,返回布尔值。如果返回值为true,将路径进行打印。PrintPath即为路径打印函数。
将用过的栈进行销毁。

2、GetMazePath

当路走不通的时候,要对路径进行回溯,走到一个岔路口,向另一个方向运动。要采用递归的方式进行回溯。
在这里插入图片描述

在上图中,当走到(1,0)位置的时候,下方向和右方向都可以前行。
如果先向下运动,当我们走到(3,1)位置时便无法运动了。向下向左走会越界,向右数组值为1,无法运动。当然,上方向我们要进行一个标记,避免向回走的情况。如下图所示:
在这里插入图片描述

暂且标记为2,因为只有0才能通,标记为其它数字也无妨。既然在(3,0)无法行动,便要回到其它位置,(2,0)显然无法走通,(1,0)的右边方向是可以的,我们便要回溯到(1,0)这个位置。
并且在运动的时候,代码无法确定此时正在走的路径能能不能到达终点(3,3)处,所以要实时得对路径在栈中进行Push(保存),或者Pop(删除)。

(1)、是否到达终点
StackPush(&path, cur);//保存路径
if (cur.row == N - 1 && cur.col == M - 1)//判断是否到达终端点
	return true;
maze[cur.row][cur.col] = 2;//标记走过的路

在每一次运动时,最先要保存一下路径,之后再判断要不要删除路径。
并且要判断是否到达迷宫的终点(数组右下角),如果以及到达终点就没有继续递归的必要了,直接返回true即可。
以及要对走过的路进行一个标记

(2)、判断下一个方向是否通路
Pos next = cur;//下一个位置坐标
next.row -= 1;//向上走
if 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值