数据结构--栈-C语言实现迷宫求解

本文基于严蔚敏《数据结构》的C语言代码,介绍如何使用栈实现穷举法解决迷宫求解问题,涉及栈操作、状态表示与路径跟踪。通过调整参数生成不同规模的迷宫实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据结构–栈C语言实现迷宫求解

  1. 前言
    代码主要根据《数据结构》(C语言版)严蔚敏提供的C语言伪代码而写,改变了其中的一些小细节。提供这个代码主要不是学习栈,而是学习穷举迷宫求解算法,另外代码中用到了二级指针,必须要对指针熟悉才行。
    运行的时候可以改变00_stack_maze.h中的相关参数来改变迷宫的规模以及迷宫中障碍的数量,开始可以调得小一些。
    程序是每隔两秒打印一次,程序中的方向用每个方向英文单词首字母表示。
    另外推荐学习视频是B站的数据结构官方视频,最后如果觉得代码可读性很差或者有错误,轻点骂。
  2. 迷宫求解思想
    迷宫求解主要思想是回溯法。
    在这里插入图片描述

在这里插入图片描述

  1. 代码
00_state.h
*预定义常量和类型 
*/

#ifndef __00_STATE_H__
#define __00_STATE_H__

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#include<windows.h>


#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2

typedef int Status;

#endif




/*
*02_stack_maze.h
*/

#include"00_state.h"
#define SleepTime 2
#define MAZE_SIZE 7
#define OBSTACLE_NUMBER 10
#define STACK_INIT_SIZE 100//存储空间初始分配量
#define STACK_INCREMENT 10//存储空间分配增量



typedef enum{
	ACCESSIBLE,
	START,
	END,
	OBSTACLE,
	MARKED,//走过的通道 
	NOT_ACCESSIBLE//走过但是退回来了 
}maze[MAZE_SIZE][MAZE_SIZE],STATE;

typedef enum{
		EAST,
		SOUTH,
		WEST,
		NORTH
}DIR;

typedef struct{
	int X;
	int Y;
}PosType;

typedef struct {
	int order;		//通道序号
	PosType seat;		//坐标
	DIR dir;			//下一个该访问的方向
}maze_block,StackElemType;//迷宫通道类型,也是栈元素 


typedef struct{
	StackElemType *base;
	StackElemType *top;
	int stacksize;//当前已经分配的存储空间 
}stack;

Status stack_init(stack * pstack);//构造空栈 
StackElemType get_top(stack stack_,StackElemType *e);//获取栈顶元素
Status pop(stack *pstack,StackElemType *e);
StackElemType get_top(stack stack_,StackElemType *e);//获取栈顶元素
Status stack_empty(stack stack_);

bool maze_path(maze  maze_, PosType start, PosType end);
void create_maze(maze maze_);//构造一个迷宫
void print_maze(maze maze_);//打印迷宫 
Status not_exist_in_stack(stack stack_,PosType pos);
Status pass(maze maze_,PosType pos,stack stack_);
void track_mark(maze maze_,PosType curpos);
STATE get_pos_state(maze maze_, PosType curpos);
PosType get_next_pos(maze maze_,PosType curpos,DIR dir);
void mark_not_accessible(maze maze_,PosType pos);
Status get_pos_dir_from_stack(stack  stack_,int i,int j,DIR * dir); 


/*
*02_stack_maze.cpp
*/
#include"02_stack_maze.h"
stack stack_;

Status stack_init(stack * pstack)//构造空栈
{
	pstack->base = (StackElemType*)malloc(STACK_INIT_SIZE*sizeof(StackElemType));
	if(!pstack->base)
		exit(OVERFLOW);
	pstack->top = pstack->base;
	pstack->stacksize = STACK_INIT_SIZE;
	return OK;
}
StackElemType get_top(stack stack_,StackElemType *e)//获取栈顶元素
{
	if(stack_.top == stack_.base)
		exit(1);
	*e = *(stack_.top-1);
	return *e; 
}

Status push(stack *pstack,StackElemType e)
{
	if(pstack->top-pstack->base>=pstack->stacksize)//指针相减
	{
		pstack->base = (StackElemType*)realloc(pstack->base,(pstack->stacksize+STACK_INCREMENT)*sizeof(StackElemType));
		if(!pstack->base)
			exit(OVERFLOW);
		pstack->top=pstack->base+pstack->stacksize;
		pstack->stacksize+=STACK_INCREMENT;
		
	}
	*(pstack->top) = e;//先赋值,然后指针上移
	pstack->top++; 
	return OK;
}

Status pop(stack *pstack,StackElemType *e)
{
	if(pstack->top==pstack->base) 
	{
		printf("栈为空\n");
		return ERROR;
	}
	else
	{
		pstack->top--;//先指针下移,然后赋值
		*e = *(pstack->top);
		return OK; 
	}
}

Status stack_empty(stack stack_)
{
	return stack_.base == stack_.top?TRUE:FALSE;
}


void print_stack(stack stack_)
{
	StackElemType *base = stack_.base;
	StackElemType *top = stack_.top;
	while(base<top)
	{
		printf("%d",base->dir);
		base++;
	}
}
Status not_exist_in_stack(stack stack_,PosType pos)//判断当前位置是否为已经走过的路径 
{
	StackElemType *base = stack_.base;
	StackElemType *top = stack_.top;
	
	if(base == top)//栈为空,当前位置不在当前路径上 
		return TRUE; 
	else
	{
		while(base<top)
		{
			if(base->seat.X == pos.X&&base->seat.Y == pos.Y)
				return FALSE; 
			else
				base++;
		}
	}
	return TRUE;
} 
Status pass(maze maze_,PosType pos,stack stack_)//当前位置可以通过,即未曾走到过的通道块
{
	 if ((maze_[pos.X][pos.Y] ==ACCESSIBLE ||maze_[pos.X][pos.Y] ==START||maze_[pos.X][pos.Y] ==END)&& not_exist_in_stack(stack_,pos))	 
	 	return TRUE;		
}


void track_mark(maze maze_,PosType curpos)//标记当前位置为已经走过 
{
	//if(maze_[curpos.X][curpos.Y] == END);
	maze_[curpos.X][curpos.Y] = MARKED;
	
}

STATE get_pos_state(maze maze_, PosType curpos)
{
	return maze_[curpos.X][curpos.Y];
}

PosType get_next_pos(maze maze_,PosType curpos,DIR dir)
{
	PosType pos = curpos;
	switch(dir)
	{
		case EAST:
			pos.Y++;
			break;
		case SOUTH:
			pos.X++;
			break;
		case WEST:
			pos.Y--;
			break;
		case NORTH:
			pos.X--;
			break;
		default:
			printf("切换方向错误\n");
			exit(1);	
	}

	return pos;
}

void mark_not_accessible(maze maze_,PosType pos)
{
	maze_[pos.X][pos.Y] = NOT_ACCESSIBLE; 
}

Status get_pos_dir_from_stack(stack  stack_,int i,int j,DIR * dir)
{
	if(stack_empty(stack_))
	{
		return FALSE;	
	}
	else
	{
		StackElemType *base = stack_.base;
		StackElemType *top = stack_.top;
		while(base<top)
		{
			if(base->seat.X == i&&base->seat.Y == j)
			{
				*dir = base->dir;
				break;
			}
			else
				base++;
		}	
	}
	return FALSE;
}
bool maze_path(maze  maze_, PosType start, PosType end)
{
	

	start.X = 1;
	start.Y = 1;
	PosType curpos = start;
	int curstep = 1;
	do{
		if(pass(maze_,curpos,stack_))//当前位置可以通过,即未曾走到过的通道块 ,纳入路径,继续前进 
		{
			if(get_pos_state(maze_,curpos) == END)
			{
					printf("找到出口,坐标:(%d,%d)\n",curpos.X,curpos.Y);
					exit(0);
			}
			else
				track_mark(maze_, curpos);
			StackElemType e;
			e.order = curstep;
			e.seat = curpos;
			e.dir = EAST;
			
			push(&stack_,e);
//			if(get_pos_state(maze_,curpos) == END)
//				return TRUE;
			curpos = get_next_pos(maze_,curpos,EAST);//当前位置通,不是出口 
			curstep++;
		//	print_maze(maze_);
		}//if pass
		else//
		{
			if(!stack_empty(stack_))
			{
				StackElemType e;
				pop(&stack_,&e);
				curpos= e.seat;
				while(e.dir ==NORTH &&!stack_empty(stack_))//栈不空且栈顶位置的四周均不可通 
				{
					mark_not_accessible(maze_,e.seat);//标记当前位置不可通过
					pop(&stack_,&e); 
					curpos = e.seat;
				}//while e.dir
				
				if(e.dir<NORTH )//换向探索 
				{
					e.dir = (DIR)(e.dir+1);
					push(&stack_,e);
					curpos = get_next_pos(maze_,curpos,e.dir);//设定当前位置是新方向上的相邻块 
				}//if e.dir 
			}//if ! stack_empty
			
		}//else 
				print_maze(maze_);	
	}while(!stack_empty(stack_));
	return FALSE;	
		
}

void create_maze(maze maze_)//迷宫为MAZE_SIZE*MAZE*SIZE,其中之间的(MAZE_SIZE-2)*(MAZE_SIZE-2)为迷宫主要部分,外面的一层作为墙壁 
{
	
	
	int i = 0;
	int j = 0;
	for(;j<MAZE_SIZE;j++)//第一行和最后一行为墙 
	{
			maze_[0][j] = OBSTACLE;
			maze_[MAZE_SIZE-1][j] =OBSTACLE;
	}
	for(;i<MAZE_SIZE;i++)//第一列和最后一列为墙
	{
			maze_[i][0] = OBSTACLE;
			maze_[i][MAZE_SIZE-1] = OBSTACLE;
	}
	
	//srand(time(0));
	int k = 0;
	
	for(; k < OBSTACLE_NUMBER; k++)
	{
		i = rand()%(MAZE_SIZE-2)+1;
		j =  rand()%(MAZE_SIZE-2)+1;
		maze_[i][j] = OBSTACLE;
	}
	
	
	
	//固定起点
	maze_[1][1] = START;
	//固定终点
	maze_[MAZE_SIZE-2][1] = END; 		
}

 void print_maze(maze maze_)//打印迷宫 
 {
 	int i = 0;
 	int j = 0;
 	for( i = 0; i<MAZE_SIZE; i++)
 	{
 		for( j = 0; j<MAZE_SIZE;j++)
 		{
 			switch(maze_[i][j])
 			{
 				case ACCESSIBLE:				
						printf(" ");
						break;
				case MARKED:
					DIR dir;
					get_pos_dir_from_stack(stack_,i,j,&dir);
 					switch(dir)
 					{
 						case EAST:
 							printf("%c",'E');break;
 						case SOUTH:
 							printf("%c",'S');break;
 						case WEST:
 							printf("%c",'W');break;
 						case NORTH:
 							printf("%c",'N');break;
 						default:
 							printf("error2");
 							break;
					 }
 					break;
 				case START:
 					printf("?");
 					break;
 				case OBSTACLE:
 					printf("#");
 					break;
 				case END:
 					printf("!");
 					break;
				case NOT_ACCESSIBLE:
					printf("$");
 					break;	
 				default:
 					printf("error");
 					break;		
			 }
				
		//	printf("%d",(int)maze_[i][j]);
		 }
		printf("\n");
	}
	Sleep(2000);
	system("cls");
	
}



int main(void)
{
	stack_init(&stack_);
	maze maze_ = {ACCESSIBLE};
	create_maze(maze_);
	PosType start,end;
	start.X = 1;
	start.Y = 1;
	end.X = MAZE_SIZE-2;
	end.Y = 1;
	print_maze(maze_);
	maze_path(maze_,start,end);
	print_maze(maze_);
	//print_stack(stack_);
	return 0;	
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值