Maze Algorithm (DFS)

1. If the stack is used for maze detection, it is called depth-first search (DFS), which is basically the same as the recursive detection idea, and can be regarded as a non-recursive version of the recursive method;

2. Using queues for maze detection is breadth-first search (BFS). The breadth-first search method takes advantage of the characteristics of queues and expands layer by layer to find walkable squares. Until the exit is found, the answer that is found first is It must be the shortest.

To use an analogy, DFS is more suitable for simulating the way a robot walks through a maze. Seeing that one direction is open, it will go on forever and return when it encounters a dead end; BFS is like standing alone at the entrance of a maze and taking out a bunch Small detectors, each small detector helps him to search for a possible path to find, the first one to find the exit sends feedback, then this person just follows the path found by this small detector to walk the maze.

Maze problem

Insert picture description here

Data structure of the maze problem

Insert picture description here

Direction test: used to record the sequence of walking the maze: bottom right and top left

Note: Here to walk the maze follow the principle of bottom right and top left
Insert picture description here
Insert picture description here

The organization of data elements in the stack: used to save the current position and direction, and then push the Box structure onto the stack

The value of di in the Box structure is between 1 and 3, which represents the first element of the dircet structure array, and each element in the direct structure array represents the direction of movement
Insert picture description here

Prevent repeating to a certain point

Insert picture description here

The path you take will be pushed onto the stack

When a dead end is encountered, a rollback will be performed. During each rollback, it will be checked whether there is a way to go. During the process of retreating, the wrong path will be popped out of the stack, and the correct path will remain in the stack.

Output the stack information in reverse order to print out the correct path

Insert picture description here

Insert picture description here

Insert picture description here

The memory loop is equivalent to judging whether the current position can move to the lower right, upper left, and four directions. If it can, push the current position element saved in temp onto the stack, then update the current position to the moved position, and then enter the memory loop to judge Can it move up, down, left, and right?

Note: temp should save the point before the current position point every time after the inner loop of the loop ends.

Conditions for the end of the inner loop: 1. Get out of the maze 2. Encounter a dead end

Outer loop function: 1. When entering the outer loop for the first time, it will update the current position coordinates to the location saved by temp, and then update the direction to temp.di+1 because it moves in order, it should be lower right and upper left , So di=0 after +1, the direction is to move to the right

2. When the memory loop encounters a dead end, it will exit the inner loop and enter the outer loop. At this time, the outer loop will pop out of the stack, popping the top element of the stack, and the element on the top of the stack that is popped is the inner loop It was found that the position could not go up, down, left, and right.

The following is the operation instructions after popping the top of the stack into the outer loop

It should be noted that the point of the element reserved by temp is the point before the current position

Insert picture description here
main.cpp

#include<iostream>
#include<string>
#include<cstdlib>
using namespace std;
#include"stack.hpp"
#define M 4
#define N 4
//迷宫   maze[M+2][N+2]
int maze[M + 2][N + 2] =
{
    
    
	{
    
    1, 1, 1, 1, 1, 1},
	{
    
     1,0,0,1,1,1 },
	{
    
     1,0,0,0,0,1 },
	{
    
     1,0,1,1,1,1 },
	{
    
     1,0,0,0,0,1 },
	{
    
     1,1,1,1,1,1 },
};

//用来记录走迷宫顺序的结构体
typedef struct {
    
    
	//int cx,int cy表示x和y方向的增量
	//cy+1:表示向右走  cy-1:向左走
	//cx+1:表示向下走  cx-1:向上走
	int cx, cy;
}Direction;
//数组中方向村粗顺序:右下左上
Direction direct[4] = {
    
     {
    
    0,1},{
    
    1,0},{
    
    0,-1},{
    
    -1,0} };

//用来记录当前位置,然后压入栈中
typedef struct {
    
    
	int x, y;//记录当前位置的坐标
	int di;//记录当前位置下一次移动的方向
}Box;

//判断是否走出迷宫的代码
//参数1:迷宫图 参数2:存放方向的数组 参数3:保存通路的栈
bool findPath(int maze[M + 2][N + 2], Direction direct[], LinkStack<Box>& s)
{
    
    
	//创建Box temp结构体来保存当前位置
	Box temp;
	//记录当前位置和方向
	int x=0, y=0, di=0;
	//记录下次移动的位置坐标
	int line=0, col=0;
	//一开始点位于迷宫maze[1][1]的位置,所以将该位置的值变为-1
	maze[1][1] = -1;
	//temp值记录当前位置,将di设置为-1
	temp = {
    
     1,1,-1 };
	//将temp记录的当前位置压入栈中
	s.push(temp);
	//进入外层循环
	while (!s.isEmpty())//栈不为空
	{
    
    
		//弹出栈顶元素
		temp = s.pop();
		//更新当前位置
		x = temp.x;
		y = temp.y;
		di = temp.di+1;
		//内层循环
		while (di < 4)//尝试四个方向
		{
    
    
			//更新下一次移动的位置坐标
			line = x+direct[di].cx;
			col = y+direct[di].cy;
			//判断下一个位置能否走
			if (maze[line][col] == 0)
			{
    
    
				//如果下一个位置能够移动,就更新temp存储当前位置的值
				temp = {
    
     x,y,di };
				//将temp结构体存储当前位置的信息压入栈中
				s.push(temp);
				//更新当前位置
				x = line;
				y = col;
				//当前位置的值改为-1,表示走过了,下次不能走
				maze[line][col] = -1;
				//判断当前位置是否为迷宫出口
				if (x == M && y == N)
				{
    
    
					//把迷宫出口也压入栈中
					temp = {
    
     x, y, di };
					s.push(temp);
					//找到出口,退出函数
					return true;
				}
				else {
    
    
					//没有找到出口,但是可以移动到下一个点,那么下一个点起始移动方向更新为右,因为移动方向顺序:右下左上
					di = 0;
				}
			}
			else 
			{
    
    
				//比如一开始要往右走:如果右方向不能走,就要改变方向移动
				di++;
			}
		}

	}
	return false;
}
//测试打印迷宫通路
void test()
{
    
    
	LinkStack<Box> s;
	findPath(maze, direct, s);
	//逆序遍历栈
	int i = 0;
	int num = s.size();
	Box* data = new Box[num];
	while (!s.isEmpty())
	{
    
    
		//头删
		data[i++] = s.getTop();
		s.pop();
	}
	//对数组进行逆序遍历
	for(int j = num-1; j >=0; j--)
	{
    
    
		cout << "(" << data[j].x << "," << data[j].y << ")" << endl;
     }

}
int main()
{
    
    
	test();
	system("pause");
	return 0;
}

stack.hpp

#include<iostream>
#include<string>
#include<cstdlib>
using namespace std;
//节点结构体
template<class Data>
struct node {
    
    
	Data data;
	node<Data>* next;
};
//链表类
template<class Data>
class LinkStack 
{
    
    
private:
	node<Data>* top;
	int num;
public:
	//不需要有参构造函数
	LinkStack();
	~LinkStack();
	void push(Data val);
	Data pop();
	Data getTop();
	bool isEmpty();
	int size();
	class Empty{
    
    };
};
template<class Data>
LinkStack<Data>::LinkStack()
{
    
    
	//这里用的是无头链表
	num = 0;
	top = NULL;
};
template<class Data>
void LinkStack<Data> :: push(Data val)
{
    
    
	//在堆区开辟一块空间,来存放第一个节点
	node<Data>* newNode = new node<Data>;
	newNode->data = val;
	//无头链表的头插法
	newNode->next = top;
	//链表指向第一个节点
	top = newNode;
	num++;
}
template<class Data>
Data LinkStack<Data>::pop()
{
    
    
	//如果链表为空,就抛出异常
	if (top == NULL)
	{
    
    
		throw Empty();
	}
	//不为空,进行头删的操作
	//先释放再头删
	//注意要保存住被删除1的节点
	node<Data>* temp = top;
	Data tempData = top->data;
	//注意:要先把top移到下一个节点,再进行释放操作
	top = top->next;
	delete temp;
	num--;
	return  tempData;
}
template<class Data>
Data LinkStack<Data>::getTop()
{
    
    
	return top->data;
}
template<class Data>
bool LinkStack<Data>::isEmpty()
{
    
    
	if (top == NULL)
		return true;
	return false;
}
template<class Data>
LinkStack<Data>::~LinkStack()
{
    
    
	while (top)
	{
    
    
		node<Data>* temp = top;
		top = top->next;
		free(temp);
     }
	node<Data>* top = NULL;
}
template<class Data>
int LinkStack<Data>::size()
{
    
    
	//计算链表的长度
	return num;
}

Test Results:
Insert picture description here

Guess you like

Origin blog.csdn.net/m0_53157173/article/details/114486303