如何使用C语言实现简单迷宫(递归和非递归实现 含图例)

1.非递归实现

简单迷宫:只有一条通路的迷宫

思路:在找迷宫通路的时候,我们往往是在给定入口(入口合法且为通路)的情况下,沿着入口的某个方向走(此方向是通路)。现给定走迷宫的方向:上、左、右、下,即优先朝“上”走,如果“上”不通,朝“左”走;如果“左” 不通,朝“右”走;“右”再不通的话,朝“下”走。每次在当前步cur可以走通的情况下,先将cur保存起来,并将其标记成已走过的步,然后判断下一步next(优先朝“上”)是否可以走通。在next可以走通的情况下,继续上述过程,直到找到出口。    但这里有一个问题,当cur步的上下左右均走不通的时候我们该怎么办呢?--->此时表明cur步走错了,我们不应该再将其保存起来,因为此时的cur不是路径的一部分,并且还应该将其标记成走错的步,然后回退到上一步,继续朝其它方向(假设开始cur是从“上”回退的,那么此时cur可以向“左”走)寻找通路。  前边提到如果cur可以走通,我们便将其保存起来,然后走next步,这里我们可以用“”保存路径。找到一个可以走通的cur便让其入栈(保存起来),如果cur步走错了的话再让其出栈(不保存走错的cur步)。这样我们便充分利用了栈“后进先出”的特性。

现给定一个简单迷宫如下图所示(0表示不通,1表示可以走通):

为了方便描述位置,我们用二维数组来表示其每个点坐标。

现给定入口坐标(3,1):

1.先判断入口坐标是否合法(坐标是否在边界,值是否为1)

2.在入口合法的情况下,先让其入栈保存,并标记成已走步(现为了简便,将其标记成2)

 3.此时优先朝入口的上方寻找通路,如果next步可以走通,入栈保存next,并将其标记成已走步2

( 如果上方不通,朝左走,如果next步可以走通,入栈保存next,并将其标记成已走步2

  如果左边不通,朝右走,如果next步可以走通,入栈保存next,并将其标记成已走步2

  如果右边不通,朝下走,如果next步可以走通,入栈保存next,并将其标记成已走步2)

 4.在每次入栈保存位置坐标之后,判断是否是出口,如果是出口,直接返回;如果不是,继续步骤3

具体寻找通路过程如下所示(上方的图形表示栈):

                                         

 源代码如下:

//Stack.h:
#pragma once

#define MAX_SIZE 100
#include <assert.h>
#include <stdio.h>

typedef Position SDataType;
typedef struct Stack
{
	SDataType array[MAX_SIZE];
	int top;      //size
}Stack;

// 初始化 
void StackInit(Stack *pStack)
{
	assert(pStack);
	pStack->top = 0;
}


// 压栈 
void StackPush(Stack *pStack, SDataType data)
{
	assert(pStack);
	if (MAX_SIZE == pStack->top)
	{
		printf("栈已满\n");
		return;
	}
	pStack->array[pStack->top] = data;
	pStack->top++;
}


//判空 空返回1
int StackEmpty(Stack *pStack)
{
	assert(pStack);
	if (0 == pStack->top)
		return 1;
	return 0;
}


// 出栈 
void StackPop(Stack *pStack)
{
	assert(pStack);
	if (StackEmpty(pStack))
	{
		printf("栈为空\n");
		return;
	}
	pStack->top--;
}



// 返回栈顶元素 
SDataType StackTop(Stack *pStack)
{
	assert(pStack);
	return pStack->array[pStack->top - 1];
}


// 返回数据个数 
int StackSize(Stack *pStack)
{
	assert(pStack);
	return pStack->top;
}
//Maze.h

//简单迷宫(非递归)
#pragma once

typedef struct Position   
{
	int _x;
	int _y;
}Position;

#define MAX_ROW  4
#define MAX_COL  4

typedef struct Maze
{
	int _map[MAX_ROW][MAX_COL];
}Maze;



//Maze.c
#include <stdio.h>
#include <assert.h>
#include "Stack.h"

//初始化迷宫
void InitMaze(Maze *m, int map[][MAX_COL])
{
	int i, j;
	if (NULL == m)
	{
		return;
	}
	for (i = 0; i < MAX_ROW; i++)
	{
		for (j = 0; j < MAX_COL; j++)
		{
			m->_map[i][j] = map[i][j];
		}
	}
}


//判断入口是否合法
int IsValidEntry(Maze *m, Position entry)
{
	assert(m);    //保证迷宫存在
	if (0 == entry._x || entry._x == MAX_ROW - 1 || 0 == entry._y || entry._y == MAX_COL - 1)   //在边界
	{
		return 1 == m->_map[entry._x][entry._y];     //如果存的是1,表示是通路;否则,不是通路
	}
	return 0;    //不在边界则一定不是合法入口
}


//判断是否是通路
int IsPass(Maze *m, Position cur)
{   //cur一定在迷宫中
	if (1 == m->_map[cur._x][cur._y])  //若cur步存的是1,则表示是通路
	{
		return 1;
	}
	return 0;
}


//判断是否是出口
int IsExit(Maze *m, Position cur, Position entry)
{
	if (cur._x == entry._x && cur._y == entry._y)  //如果cur等于entry(入口),表明不是出口
	{
		return 0;
	}
	if (0 == cur._x || cur._x == MAX_ROW - 1 || 0 == cur._y || cur._y == MAX_COL - 1) //在cur不是入口的前提下,如果cur在边界,则表明是出口
	{
		return 1;
	}
	return 0;
}


//entry表示迷宫的入口,栈s保存走过的路径
void PassMaze(Maze *m, Position entry, Stack *s)
{
	Position cur,next;
	//先判断入口是否合法,不合法直接退出
	if (!IsValidEntry(m, entry))
	{
		printf("非法的迷宫入口!\n");
		return;
	}

	StackPush(s,entry);    //入口合法,让其入栈

	while (!StackEmpty(s))    //栈不为空,表明有出口。若迷宫没有入口,则cur会一直出栈,直到空
	{
		cur = StackTop(s);  //取栈顶(前提:栈不为空)
		m->_map[cur._x][cur._y] = 2; //标记一下,代表此位置已经走过

		if (IsExit(m, cur,entry))     //检测cur是否是出口,若为出口,直接返回退出
		{
			return;
		}

		//上
		next = cur;
		next._x -= 1;
		if (IsPass(m, next))
		{
			StackPush(s, next);    //下一步可以走通,让其入栈,先保存起来
			continue;

		}

		//左
		next = cur;
		next._y -= 1;
		if (IsPass(m, next))
		{
			StackPush(s, next);   //下一步可以走通,让其入栈,先保存起来
			continue;

		}

		//右
		next = cur;
		next._y += 1;
		if (IsPass(m, next))
		{
			StackPush(s, next);    //下一步可以走通,让其入栈,先保存起来
			continue;

		}

		//下
		next = cur;
		next._x += 1;
		if (IsPass(m, next))
		{
			StackPush(s, next);     //下一步可以走通,让其入栈,先保存起来
			continue;
		}

		StackPop(s);     //上下左右均走不通,表明cur步走错了,让其出栈,不要出现在最终路径中
		m->_map[cur._x][cur._y] = 3;     //标记走错的步为3
	}

}


//打印迷宫
void PrintMaze(Maze *m, int map[][MAX_COL])
{
	int i, j;
	if (NULL == m)
	{
		return;
	}
	for (i = 0; i < MAX_ROW; i++)
	{
		for (j = 0; j < MAX_COL; j++)
		{
			printf("%d ", m->_map[i][j]);
		}
		printf("\n");
	}
}


//打印最终路径
void Print(Stack *s)
{
	Position top;
	while (StackSize(s) > 1)
	{
		top = StackTop(s);
		StackPop(s);
		printf("(%d,%d) <- ", top);
	}
	top = StackTop(s);
	printf("(%d,%d)\n", top);
}




void TestMaze()
{
	int map[MAX_ROW][MAX_COL] = { { 0, 0, 0, 0},
	                              { 0, 1, 0, 0},
	                              { 0, 1, 1, 1},
	                              { 0, 1, 0, 0}};
	Stack s;
	Position entry;
	Maze m;
	InitMaze(&m,map);
	PrintMaze(&m, map);
	printf("\n");

	StackInit(&s);
	entry._x = 3;
	entry._y = 1;
	PassMaze(&m, entry, &s);
	PrintMaze(&m, map);
	printf("\n");
	Print(&s);
	
}

最终打印出来的路径如下图所示:

 

2.递归实现

思路:在给定入口(入口合法且为通路)的情况下,我们可以把入口的下一步,比如入口上方(上方为通路)作为新的入口点继续走迷宫,直到走完整个迷宫。

源代码如下:

//MazeR.h
//简单迷宫(递归)
#pragma once

typedef struct Position
{
	int _x;
	int _y;
}Position;

#define MAX_ROW  4
#define MAX_COL  4

typedef struct Maze
{
	int _map[MAX_ROW][MAX_COL];
}Maze;




//MazeR.c
#include <stdio.h>
#include <assert.h>


//初始化
void InitMaze(Maze *m, int map[][MAX_COL])
{
	int i, j;
	if (NULL == m)
	{
		return;
	}
	for (i = 0; i < MAX_ROW; i++)
	{
		for (j = 0; j < MAX_COL; j++)
		{
			m->_map[i][j] = map[i][j];
		}
	}
}


//判断入口是否合法
int IsValidEntry(Maze *m, Position entry)
{
	assert(m);    //保证迷宫存在
	if (0 == entry._x || entry._x == MAX_ROW - 1 || 0 == entry._y || entry._y == MAX_COL - 1)   //在边界
	{
		return 1 == m->_map[entry._x][entry._y];    //如果存的是1,表示是通路;否则,不是通路
	}
	return 0;     //不在边界则一定不是合法入口
}


//判断是否是通路
int IsPass(Maze *m, Position cur)
{   //cur一定在迷宫中
	if (1 == m->_map[cur._x][cur._y])  //若cur步存的是1,则表示是通路
	{
		return 1;
	}
	return 0;
}


//判断是否是出口
int IsExit(Maze *m, Position cur, Position entry)
{
	if (cur._x == entry._x && cur._y == entry._y)  //如果cur等于entry(入口),表明不是出口
	{
		return 0;
	}
	if (0 == cur._x || cur._x == MAX_ROW - 1 || 0 == cur._y || cur._y == MAX_COL - 1) //在cur不是入口的前提下,如果cur在边界,则表明是出口
	{
		return 1;
	}
	return 0;
}

int _PassMaze(Maze *m, Position entry, Position cur)
{
	Position next;
	if (IsPass(m, cur))
	{
		m->_map[cur._x][cur._y] = 2;    //标记一下,代表此位置已经走过

		if (IsExit(m, cur, entry))     //检测cur是否是出口,若为出口,直接返回退出
		{
			return 1;
		}

		//上
		next = cur;
		next._x -= 1;
		if (_PassMaze(m, entry, next))   //递归时,next为下一次的入口,继续走迷宫
		{
			return 1;
		}

		//左
		next = cur;
		next._y -= 1;
		if (_PassMaze(m, entry, next))    //递归时,next为下一次的入口,继续走迷宫
		{
			return 1;
		}

		//右
		next = cur;
		next._y += 1;
		if (_PassMaze(m, entry, next))     //递归时,next为下一次的入口,继续走迷宫
		{
			return 1;
		}

		//下
		next = cur;
		next._x += 1;
		if (_PassMaze(m, entry, next))      //递归时,next为下一次的入口,继续走迷宫
		{
			return 1;
		}
		m->_map[cur._x][cur._y] = 3;    //cur步走错了,标记成3
	}
	return 0;
}


//entry表示入口,栈s保存走过的路径
void PassMaze(Maze *m, Position entry)
{
	//先判断入口是否合法,不合法直接退出
	if (!IsValidEntry(m, entry))
	{
		printf("非法的迷宫入口!\n");
		return;
	}
	_PassMaze(m, entry, entry);      //第一个entry表示入口,第二个entry表示当前入口

}


//打印迷宫
void PrintMaze(Maze *m, int map[][MAX_COL])
{
	int i, j;
	if (NULL == m)
	{
		return;
	}
	for (i = 0; i < MAX_ROW; i++)
	{
		for (j = 0; j < MAX_COL; j++)
		{
			printf("%d ", m->_map[i][j]);
		}
		printf("\n");
	}
}






void TestMaze()
{
	int map[MAX_ROW][MAX_COL] = { { 0, 0, 0, 0 },
	                              { 0, 1, 0, 0 },
	                              { 0, 1, 1, 1 },
	                              { 0, 1, 0, 0 } };
	
	Position entry;
	Maze m;
	InitMaze(&m, map);
	PrintMaze(&m, map);
	printf("\n");

	
	entry._x = 3;
	entry._y = 1;
	PassMaze(&m, entry);
	PrintMaze(&m, map);
	printf("\n");
	
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值