迷宫问题 (上)栈 回溯法

迷宫问题的总体思路是,从迷宫的入口出发,沿着某一个方向向前试探,若能够行得通,则继续往前走,否则原来返回,再换另一个方向继续试探,直到所有可能的通路都被试探过,为了保证在任何一个位置都能够原来返回,需要设置一个堆栈结构来保存从入口到当前位置的路径。因为可以需要保证能够返回所在节点,所以需要回溯法能够保证回到走过的节点。

本文的解法 参考 《数据结构 C》 李春葆 – 非迭代法, 迭代法 原创。迷宫用二维数组 A 表示: 最外围的1 表示墙, 内部1表示墙, 0 表示通路。使用非迭代方法, C程序如下 

int findPath(int in_x, int in_y, int out_x, int out_y)
{

	int A[10][10] = {
  		{1,1,1,1,1,1,1,1,1,1},
 		{1,0,0,1,0,0,0,1,0,1},
  		{1,0,0,1,0,0,0,1,0,1},
  		{1,0,0,0,0,1,1,0,0,1},
  		{1,0,1,1,1,0,0,0,0,1},
  		{1,0,0,0,1,0,0,0,0,1},
  		{1,0,1,0,0,0,1,0,0,1},
  		{1,0,1,1,1,0,1,1,0,1},
  		{1,1,0,0,0,0,0,0,0,1},
  		{1,1,1,1,1,1,1,1,1,1}
	};

	// 栈用于存储走过的节点
	struct
	{
		int x;
		int y;
		int next; // how many ways to go or left to go in this node
	}st[MAXSTACKSIZE];
	int top = -1;

	// 将入口添加到栈中
	top++;
	st[top].x = in_x;
	st[top].y = in_y;
	st[top].next = -1;
	A[in_x][in_y] = -1;

	int cnt_i, cnt_j, cnt_next, find_way;
	while(top > -1)
	{
		cnt_i = st[top].x; cnt_j = st[top].y;
		cnt_next = st[top].next; // 取得当前节点 同时查看当前节点还有几个下一个节点可以走


		//printf("at [%d %d]\n", cnt_i, cnt_j);
		// find the path
		if(cnt_i == out_x && cnt_j == out_y)
		{
			printf("\n\nFind the path:");
			for(int k = 0; k <= top; k++)
			{
				printf("\t[%d %d]", st[k].x, st[k].y);
				if(k % 5 == 0)
				{
					printf("\n");
				}
			}
			printf("\n\n");
		} // end of find path

		// find next way to go
		find_way = 0;
		while(cnt_next < 4 && find_way == 0)
		{
			cnt_next++;
			switch(cnt_next)
			{
			case 0: cnt_i = st[top].x - 1; cnt_j = st[top].y; break;
			case 1: cnt_i = st[top].x; cnt_j = st[top].y + 1; break;
			case 2: cnt_i = st[top].x + 1; cnt_j = st[top].y; break;
			case 3: cnt_i = st[top].x; cnt_j = st[top].y - 1; break;
			}
			if(0 == A[cnt_i][cnt_j]) find_way = 1; // 有路可以走
		}
		if(find_way == 1)
		{  // find way and stack it
			st[top].next = cnt_next;
			top++;
			st[top].x = cnt_i;
			st[top].y = cnt_j;
			st[top].next = -1;
			A[cnt_i][cnt_j] = -1;
		}else
		{   // do not find way in this node; 
			// pop out the node
			A[st[top].x][st[top].y] = 0;
			top --;
		}
	}
	return 0; // no way to go and return 0;
}

 

使用迭代方法

int top_iter;
int A_iter[10][10] = {
		{1,1,1,1,1,1,1,1,1,1},
		{1,0,0,1,0,0,0,1,0,1},
		{1,0,0,1,0,0,0,1,0,1},
		{1,0,0,0,0,1,1,0,0,1},
		{1,0,1,1,1,0,0,0,0,1},
		{1,0,0,0,1,0,0,0,0,1},
		{1,0,1,0,0,0,1,0,0,1},
		{1,0,1,1,1,0,1,1,0,1},
		{1,1,0,0,0,0,0,0,0,1},
		{1,1,1,1,1,1,1,1,1,1}
};
int find_way_iter = 0;	

int findPathIterative(int in_x, int in_y, int out_x, int out_y)
{	
	top_iter = -1;
	top_iter++;
	st_iter[top_iter].x = in_x;
	st_iter[top_iter].y = in_y;
	A_iter[in_x][in_y] = -1;

	_findPathIterative(in_x, in_y, out_x, out_y);
	if(find_way_iter == 0)
	{
		printf("No way to go");
	}
	return 0;
}

void _findPathIterative(int in_x, int in_y, int out_x, int out_y)
{
	// find the path
	if(in_x == out_x && in_y == out_y)
	{
		printf("\n\nFind the path:");
		find_way_iter = 1;
		for(int k = 0; k <= top_iter; k++)
		{
			printf("\t[%d %d]", st_iter[k].x, st_iter[k].y);
			if(k % 5 == 0)
			{
				printf("\n");
			}
		}
		printf("\n\n");
	} // end of find path
	
	// up node to iterate
	if(A_iter[in_x - 1][in_y] == 0)
	{
		PushtoStack(in_x - 1, in_y); // push the node into stack and add covered tag
		_findPathIterative(in_x - 1, in_y, out_x, out_y);
		PopFromStack(); // pop out the node and remove the tag
	}
	// right node to iterate
	if(A_iter[in_x][in_y+1] == 0)
	{
		PushtoStack(in_x, in_y + 1);
		_findPathIterative(in_x, in_y + 1, out_x, out_y);
		PopFromStack();
	}
	// bottom node to iterate
	if(A_iter[in_x + 1][in_y] == 0)
	{
		PushtoStack(in_x + 1, in_y);
		_findPathIterative(in_x + 1, in_y, out_x, out_y);
		PopFromStack();
	}
	// left node to iterate
	if(A_iter[in_x][in_y - 1] == 0)
	{
		PushtoStack(in_x, in_y - 1);
		_findPathIterative(in_x, in_y - 1, out_x, out_y);
		PopFromStack();
	}
	
}

void PopFromStack()
{
	A_iter[st_iter[top_iter].x][st_iter[top_iter].y] = 0; // out of this node
	top_iter --;
}

void PushtoStack(int x, int y)
{
	top_iter++;
	st_iter[top_iter].x = x;
	st_iter[top_iter].y = y;
	A_iter[x][y] = -1; // covered this node
}

上述迭代方法 没有办法找到最优解(最短路径)。

只能找到所有路径。

比较上述两个方法

迭代方法 用时303ms; 非迭代方法587ms

迭代方法明显优于非迭代方法,并且易于理解。

 

 

 

    原文作者:迷宫问题
    原文地址: https://blog.csdn.net/dannyPolyu/article/details/9207885
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞