深度优先搜索(堆栈)解决走迷宫问题

时间:2021-11-13 20:32:15

1 问题

定义一个二维数组:

int  maze[5][5] = {

        0,1, 0, 0, 0,

        0,1, 0, 1, 0,

        0,0, 0, 0, 0,

        0,1, 1, 1, 0,

        0,0, 0, 1, 0,

};

它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的路线。[Linux C编程一站式学习 12.3题目,没读懂题目要求是找到所有的路线还是一条路线]。


2 用堆栈来实现深度优先过程

在迷宫中可以走的路(数组maze中值为0的元素的坐标)用堆栈数据结构保存[在迷宫中(数组中当前坐标为0的元素的坐标)先探索是否可以往右、下、左、上的顺序走,如果可以就将这些右边的、下边的、左边的、上面的元素的坐标记录下来]。然后再将栈顶的元素坐标取出来(上,左,下,右)按照相同的方式探索此元素周围的其它元素,当出现走不通情况时,由于堆栈的每次出栈操作,堆栈的下一次出栈操作就会使得另外一个方向的元素坐标被压出来。对于左和右来说,在迷宫中往上和下走总是优先,故而有深度优先的特点。


3  C代码

平台:debain GNU/Linux 3.2.04

代码中将maze[4][3]由原来的1改为0,以验证程序向左和向上搜索通道。从左下角到右下角所有的通路代码:

/* platform:	debian	GNU/Linux 3.2.04
 * filename:	deepth_fisrt.c
 * brife:	Sovle the maze problem by using stack
 * author:	One fish
 * date:	2014.7.19 -- Saturday
 */
#include <stdio.h>



//--------------Macro definiton-----------------------------
#define	ROAD		0
#define AREADY_WALK	2
#define ROW		5
#define	COL		5
#define	N		ROW * COL
//--------------Macro definiton-----------------------------



/******************** Global varibales definition ************/
static int maze[ROW][COL] = {
	{0, 1, 0, 0, 0},
	{0, 1, 0, 1, 0},
	{0, 0, 0, 0, 0},
	{0, 1, 1, 1, 0},
	{0, 0, 0, 0, 0}
};		//The maze, 0 is the road, 1 is the wall


static int top;	//Index of stack top's next location
static struct point {
	int row;
	int col;
}p, stack[N];	//p is the maze's location, stack is the location of maze's element which equals zero
/******************** Global varibales definition ************/



//------------------Function deckaration--------------------
void go_maze(void);
void maze_visit(int row, int col, struct point p);
void print_maze(void);
void stack_push(struct point p);
struct point stack_pop(void);
int stack_empty(void);




int main(void)
{
	go_maze();

	return 0;
}



/* @brife:	Print maze elements
 * @arg:	None
 * @rel:	None
 */
void print_maze(void)
{
	int i, j;
	for(i = 0; i < ROW; ++i){
		for(j = 0; j < COL; ++j)
			printf("%d\t", maze[i][j]);
		printf("\n");
	}
	printf("----------------------------------\n");
}

/* @brife:	Finde one road in maze
 * @arg:	None
 * @rel:	None
 */
void go_maze(void)
{
	//Init first element
	p.row = p.col	= 0;
	maze[p.row][p.col]	= AREADY_WALK;
	stack_push(p);


	while(!stack_empty()){
		//The current location
		p	= stack_pop();
		
		//If only need one road
		//if(ROW - 1 == p.row && COL - 1 == p.col)
		//	break;
		//Look if may go right direction
		if(p.col < COL - 1 && ROAD == maze[p.row][p.col + 1]){
			maze_visit(p.row, p.col + 1, p);
		}
		
		//Look if may go down
		if(p.row < ROW - 1 && ROAD == maze[p.row + 1][p.col]){
			maze_visit(p.row + 1, p.col, p);
		}

		//Look if may go left
		if(p.col > 0 && ROAD == maze[p.row][p.col - 1]){
			maze_visit(p.row, p.col - 1, p);
		}

		//Look if may go up
		if(p.row > 0 && ROAD == maze[p.row - 1][p.col]){
			maze_visit(p.row - 1, p.col, p);
		}
		
		//Show current element's road
		print_maze();
	}
}

/* @brife:	Mark(push in stack) the zero elments of stack, those elemets round the current element
 * @arg:	row, col is the zero element(around the current elemet)'s row, col index.p is the current element's location
 * @rel:	None
 */
void maze_visit(int row, int col, struct point p)
{
	struct point around_p = {row, col};
	maze[row][col]	= AREADY_WALK;
	stack_push(around_p);
}

/*@brife:	Push the p to stack top
 *@arg:		p is the zero element of maze
 *@rel:		None
 */
void stack_push(struct point p)
{
	if(top < N){
		stack[top++]	= p;
	}
}

/* @brife:	Get the top element of stack
 * @arg:	None
 * @rel:	The top element of stack if stack is not empty, -1 if stack is empty
 */
struct point stack_pop(void)
{
	if(!stack_empty()){
		return stack[--top];
	}else{
		struct point p = {-1, -1};
		return p;
	}
}

/* @brife:	Judge if stack is empty
 * @arg:	None
 * @rev:	Stck is empty when return 1, oterwise return 0
 */
int stack_empty(void)
{
	if(top < 0)
		return 1;
	else
		return 0;
}

在Linux终端下编译通过后并执行文件:

gcc   deepth_fisrt.c   -o  deepth_fisrt

./deepth_fisrt > all.txt

all.txt内容如下:

2	1	0	0	0	
2	1	0	1	0	
0	0	0	0	0	
0	1	1	1	0	
0	0	0	0	0	
----------------------------------
2	1	0	0	0	
2	1	0	1	0	
2	0	0	0	0	
0	1	1	1	0	
0	0	0	0	0	
----------------------------------
2	1	0	0	0	
2	1	0	1	0	
2	2	0	0	0	
2	1	1	1	0	
0	0	0	0	0	
----------------------------------
2	1	0	0	0	
2	1	0	1	0	
2	2	0	0	0	
2	1	1	1	0	
2	0	0	0	0	
----------------------------------
2	1	0	0	0	
2	1	0	1	0	
2	2	0	0	0	
2	1	1	1	0	
2	2	0	0	0	
----------------------------------
2	1	0	0	0	
2	1	0	1	0	
2	2	0	0	0	
2	1	1	1	0	
2	2	2	0	0	
----------------------------------
2	1	0	0	0	
2	1	0	1	0	
2	2	0	0	0	
2	1	1	1	0	
2	2	2	2	0	
----------------------------------
2	1	0	0	0	
2	1	0	1	0	
2	2	0	0	0	
2	1	1	1	0	
2	2	2	2	2	
----------------------------------
2	1	0	0	0	
2	1	0	1	0	
2	2	0	0	0	
2	1	1	1	2	
2	2	2	2	2	
----------------------------------
2	1	0	0	0	
2	1	0	1	0	
2	2	0	0	2	
2	1	1	1	2	
2	2	2	2	2	
----------------------------------
2	1	0	0	0	
2	1	0	1	2	
2	2	0	2	2	
2	1	1	1	2	
2	2	2	2	2	
----------------------------------
2	1	0	0	2	
2	1	0	1	2	
2	2	0	2	2	
2	1	1	1	2	
2	2	2	2	2	
----------------------------------
2	1	0	2	2	
2	1	0	1	2	
2	2	0	2	2	
2	1	1	1	2	
2	2	2	2	2	
----------------------------------
2	1	2	2	2	
2	1	0	1	2	
2	2	0	2	2	
2	1	1	1	2	
2	2	2	2	2	
----------------------------------
2	1	2	2	2	
2	1	2	1	2	
2	2	0	2	2	
2	1	1	1	2	
2	2	2	2	2	
----------------------------------
2	1	2	2	2	
2	1	2	1	2	
2	2	2	2	2	
2	1	1	1	2	
2	2	2	2	2	
----------------------------------
2	1	2	2	2	
2	1	2	1	2	
2	2	2	2	2	
2	1	1	1	2	
2	2	2	2	2	
----------------------------------
2	1	2	2	2	
2	1	2	1	2	
2	2	2	2	2	
2	1	1	1	2	
2	2	2	2	2	
----------------------------------
2	1	2	2	2	
2	1	2	1	2	
2	2	2	2	2	
2	1	1	1	2	
2	2	2	2	2	
----------------------------------
2	1	2	2	2	
2	1	2	1	2	
2	2	2	2	2	
2	1	1	1	2	
2	2	2	2	2	
----------------------------------
多了几行。

从左下角到右下角深度优先一个通路代码只需要将从左下角到右下角所有的通路代码中void go_maze(void);函数中if语句的注释取消即可:

	while(!stack_empty()){
		//The current location
		p	= stack_pop();
		
		//If only need one road
		//if(ROW - 1 == p.row && COL - 1 == p.col)
		//	break;
		//Look if may go right direction
		if(p.col < COL - 1 && ROAD == maze[p.row][p.col + 1]){
			maze_visit(p.row, p.col + 1, p);
		}

在Linux终端下编译通过后并执行文件:

gcc   deepth_fisrt.c  -o  deepth_fisrt

./deepth_fisrt > once.txt


once.txt内容如下:

2	1	0	0	0	
2	1	0	1	0	
0	0	0	0	0	
0	1	1	1	0	
0	0	0	0	0	
----------------------------------
2	1	0	0	0	
2	1	0	1	0	
2	0	0	0	0	
0	1	1	1	0	
0	0	0	0	0	
----------------------------------
2	1	0	0	0	
2	1	0	1	0	
2	2	0	0	0	
2	1	1	1	0	
0	0	0	0	0	
----------------------------------
2	1	0	0	0	
2	1	0	1	0	
2	2	0	0	0	
2	1	1	1	0	
2	0	0	0	0	
----------------------------------
2	1	0	0	0	
2	1	0	1	0	
2	2	0	0	0	
2	1	1	1	0	
2	2	0	0	0	
----------------------------------
2	1	0	0	0	
2	1	0	1	0	
2	2	0	0	0	
2	1	1	1	0	
2	2	2	0	0	
----------------------------------
2	1	0	0	0	
2	1	0	1	0	
2	2	0	0	0	
2	1	1	1	0	
2	2	2	2	0	
----------------------------------
2	1	0	0	0	
2	1	0	1	0	
2	2	0	0	0	
2	1	1	1	0	
2	2	2	2	2	
----------------------------------


数组中2表示走过的路,那么从左上角严着有2的路线到右下角都是迷宫中的通道。如果寻找通道的方法不变(右,下,左,上),继续寻找新道路的顺序也变为右,下,左,上,那么就可以实现广度优先搜索。队列就有先进先出的特性,故而只要将以上代码的数据结构换成队列,那么就可以实现广度优先搜索来解决迷宫问题。一般为了回收利用队列中的存储空间,会采用环形队列作为程序数据结构来解决问题。除此之外,在堆栈数据结构上改变寻找通道的顺序也可以实现广度优先搜索,队列也可以实现深度优先搜索(未编程验证)。


LBNote Over.