Stack solving maze solving problem

Stack solving maze solving problem

Label (space separated): stack, backtracking algorithm

1, Introduce

  • Find the maze path needs to use the backtracking method. Finding the maze path is a good application of the backtracking method. The data structure stack is used in the process of backtracking!

  • Backtracking method: for a problem with many nodes and several search branches at each node, the original problem is decomposed into several sub problems; When a node is searched and it is found that the search cannot continue, the search process will be traced back (fallback) to the previous node of the node and continue to search other branches outside the node that have not been searched; If it is found that the node can no longer be searched, let the search process go back to the previous node of the node and continue the search process; Such a search process continues until the solution of the problem is searched or all searchable branches have no solution.

2, Stack characteristics

  • Stack is a linear table, but it is a linear table with limited operation, which can only be operated at one end. The end in and out is called the top of the stack and the other end is called the base. Stacks can be stored sequentially or chained. The following code uses sequential storage to implement the stack.

  • Structure diagram of stack:

Where, base points to the bottom of the stack and top points to the top of the stack. Note: the stack can only operate at one end, last in first out, which is the key feature of the stack, that is, it is not allowed to find, value, insert, delete and other operations in the middle.

3, Concrete implementation

  • Construction of sequence stack:
    Here, the implementation code of the sequence stack is written in the header file maze.h for the next maze solution
#pragma once
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100
typedef struct _Position{//Labyrinth coordinates
	int _x;
	int _y;
}Position;
#define MaxSize 128 / / allocate space in advance. This value is estimated and determined according to actual needs
typedef Position ElemType;
typedef struct _SqStack{
	ElemType *base; //Stack bottom pointer
	ElemType *top; //Stack top pointer
}SqStack;

bool InitStack(SqStack &S) //Construct an empty stack S
{
	S.base = new ElemType[MaxSize];//Allocate a space with a maximum capacity of Maxsize for the sequential stack
	if (!S.base) //Space allocation failed
		return false;
	S.top=S.base; //top is initially base, and the stack is empty
	return true;
}

bool PushStack(SqStack &S, ElemType e) // Insert element e as the new stack top element
{

	if (S.top-S.base == MaxSize) //Stack full
		return false;
	*(S.top++) = e; //Element e is pushed into the top of the stack, and then the pointer at the top of the stack is increased by 1, which is equivalent to * S.top=e;S.top++;
	return true;
}

bool PopStack(SqStack &S, ElemType &e) //Delete the stack top element of S and temporarily store it in the variable e
{
	if (S.base == S.top){ //Stack empty
		return false;
	}
	e = *(--S.top); //The stack top pointer minus 1 assigns the stack top element to e
	return true;
}

ElemType* GetTop(SqStack &S) //Returns the stack top element of S, and the stack top pointer remains unchanged
{
	if (S.top != S.base){ //Stack is not empty
		return S.top - 1; //Returns the value of the stack top element, and the stack top pointer remains unchanged
	}else{
		return NULL;
	}
}

int GetSize(SqStack &S){//Returns the number of elements in the stack
	return (S.top-S.base);
}

bool IsEmpty(SqStack &S){//Determine whether the stack is empty
	if (S.top == S.base){
		return true;
	}else{
		return false;
	}
}

void DestoryStack(SqStack &S){//Destroy stack
	if(S.base){

		free(S.base);
		S.base = NULL;
		S.top = NULL;
	}
}

  • Maze solution path part code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "maze.h"
#include <assert.h>
#define ROW 6
#define COL 6
typedef struct _Maze{
	int map[ROW][COL];
}Maze;

void InitMaze(Maze* m, int map[ROW][COL]) //Initialization of maze
{
	for (int i = 0;i< ROW ;++i)
	{
		for (int j = 0; j < COL; ++j)
		{
			m->map[i][j] = map[i][j];
		}
	}
}

void PrintMaze(Maze* m) //Print maze
{
	for (int i = 0; i < ROW; ++i)
	{
		for (int j = 0; j < COL; ++j)
		{
			printf("%d ",m->map[i][j]);
		}
		printf("\n");
	}
	printf("\n");
}

int IsValidEnter(Maze* m, Position cur) //Determine whether it is a valid entry
{
	assert(m);
	if ((cur._x == 0 || cur._x == ROW - 1)
		|| (cur._y == 0 || cur._y == COL - 1)
		&& (m->map[cur._x][cur._y] == 1))
		return 1;
	else
		return 0;
}

int IsNextPass(Maze* m,Position cur, Position next) //Judge whether the next node of the current node can go through
{
	assert(m);
	//Judge whether the next node is the next node of cur
	if(((next._x == cur._x) && ((next._y == cur._y+1)||(next._y ==
		cur._y-1))) //On the same line and adjacent
		||((next._y == cur._y) && ( (next._x == cur._x+1)||(next._x ==
		cur._x-1)))){//Or on the same column and adjacent
			//Judge whether the next node is in the maze
			if (((next._x >= 0 && next._x < ROW) || (next._y >= 0 && next._y
				< COL))
				&&(m->map[next._x][next._y] == 1)){
					return 1;
			}
	}
	return 0;
}

int IsValidExit(Maze* m, Position cur,Position enter) //Judge whether the current node is a valid maze exit
{
	assert(m);
	//Here, we must first ensure that the node is not an entry point. Secondly, as long as it is at the boundary of the maze
	if ((cur._x != enter._x || cur._y != enter._y)
		&& ((cur._x == 0 || cur._x == ROW - 1)
		|| (cur._y == 0 || cur._y == COL - 1)))
	{
		return 1;
	}
	else
		return 0;
}
//Core code:
int PassMaze(Maze* m,Position enter,SqStack* s) //Find maze path
{
	assert(m && IsValidEnter(m,enter) == 1); //Judge the legitimacy of the entrance of the given maze
	Position cur = enter;
	Position next;
	PushStack(*s, cur); //First, press the entrance of the maze into the stack
	m->map[cur._x][cur._y] = 2; //Change the entry value to 2
	//PrintMaze(m);
	while (!IsEmpty(*s)) {
		cur = *GetTop(*s);
		//printf("cur: %d %d\n",cur._x, cur._y);
		if (IsValidExit(m,cur,enter) == 1) //Determine whether the current position is an exit
			return 1;
		//Try to step to the left: see if the left node of the current node can go through
		next = cur;
		next._y = cur._y - 1;
		if (IsNextPass(m, cur, next) == 1)
		{
			PushStack(*s, next);
			m->map[next._x][next._y] = m->map[cur._x][cur._y] + 1;
			//PrintMaze(m);
			continue;
		}
		//Try to step up: see if the previous node of the current node can go through
		next = cur;
		next._x = cur._x - 1;
		if (IsNextPass(m,cur,next) == 1) //When the next node can go through, push it into the stack
		{
			PushStack(*s,next);
			m->map[next._x][next._y] = m->map[cur._x][cur._y]+1; //The value of the next node is equal to the value of the cur node plus 1
				//PrintMaze(m);
				continue;
		}
		//Right: check whether the right node of the current node can go through
		
		next = cur;
		next._y = cur._y + 1;
		if (IsNextPass(m, cur,next) == 1)
		{
			PushStack(*s, next);
			m->map[next._x][next._y] = m->map[cur._x][cur._y] + 1;
			//PrintMaze(m);
			continue;
		}
		//Next: check whether the next node of the current node can go through
		next = cur;
		next._x = cur._x + 1;
		if (IsNextPass(m, cur,next) == 1)
		{
			PushStack(*s, next);
			m->map[next._x][next._y] = m->map[cur._x][cur._y] + 1;
			//PrintMaze(m);
			continue;
		}
		//If you go here, it means that the four directions of the current node cannot go through. Go back to see if the direction of the previous node that has not been traversed can still go through
		Position tmp;
		PopStack(*s, tmp);
	}
	return 0;
}

  • Test code:
int main()
{
	int map[ROW][COL] = { //Depict the maze with a two-dimensional array: 1 represents the path and 0 represents the wall
		0,0,1,0,0,0,
		0,0,1,1,1,0,
		0,0,1,0,0,0,
		0,1,1,1,1,0,
		0,0,1,0,1,0,
		0,0,0,0,1,0
	};
	Maze m;
	Position enter; //Labyrinth entrance
	enter._x = 0;
	enter._y = 2;
	InitMaze(&m, map);
	PrintMaze(&m);

	SqStack s; //Define the stack and save the coordinate track that has been passed for easy backtracking
	InitStack(s); //Initial of stack
	int ret = PassMaze(&m,enter,&s); //Use stack and backtracking to solve the maze
	if(ret){
		printf("congratulations! Finally found the exit~\n");
	}else {
		printf("I'm not stupid! There is really no exit~\n");
	}
	PrintMaze(&m);
	system("pause");
	return 0;
}

4, Output results:

  • Print the initial maze. 1 represents that the current position is reachable and 0 represents that it is not reachable.
  • The code sets the entry address of the maze (in the case of legal entry address) to 2, and presses the entry address on the stack. Each node can go in four directions, traversing in the order of left, top, right and bottom. If you can't get through, go back to the previous position and get the top element out of the stack.
  • The value of the next position in the array is the value of the current position in the array plus 1 (except for the case of fallback, which is valid only when traversing the non traversed position).

    Actual path: 2-3-4-5-4-3-4-5-6-5-6-7-8-9

Tags: Algorithm data structure

Posted on Sun, 05 Sep 2021 14:31:31 -0400 by e11even