栈的应用--迷宫求解

栈的应用–迷宫求解

思路: 从一个起点(1,1)坐标开始, 依次判断它的右,下,左,上, 方位能不能走 如果能就直接走, 每走一步将这个位置的坐标入栈,
并且标记为2, 若都不能走, 说明走到死路了, 要开始回溯,走过没有走过标记为3 回溯时就是把入栈的坐标出栈, 即可原路返回,
每返回一步就重新再判断它的 右,下,左,上, 能不能走,直到找到终点(8,8)坐标,否则没有通路

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <malloc.h>			//动态存储分配函数头文件,用于栈的存储空间的分配


typedef int DirectiveType;		//下一个通道的方向
#define RANGE 100				//迷宫大小
#define STACK_INIT_SIZE 100		//定义栈的初始大小
#define STACKINCREMENT 10		//定义栈的存储增量,在栈长度越界时
#define OK 1
#define ERROR 0

#define ROW 10					//迷宫的行数
#define COL 10					//迷宫的列数
typedef int Status;

typedef struct{
	int m,n;
	int arr[RANGE][RANGE];		//迷宫数组
}MazeType;						//迷宫的类型

typedef struct{
	int row;					//迷宫的行
	int col;					//迷宫的列
}PosType;						//坐标(row,col)

typedef struct{
	int step;					//当前位置路径的序号
	PosType seat;				//当前位置坐标位置
	DirectiveType di;			//往下一个坐标位置的方向
}SElemType;

typedef struct{
	SElemType *base;			//栈底
	SElemType *top;				//栈顶
	int stacksize;				//栈的大小
}SqStack;						//定义栈



//初始化栈
Status InitStack(SqStack &s){
	s.base = (SElemType *)malloc (STACKINCREMENT * sizeof (SElemType ));
	if(!s.base ){
		exit(-2);
	}
	s.top = s.base ;
	s.stacksize = STACK_INIT_SIZE;
	return OK;
}


//当栈是不为空时,返回栈顶元素
Status GetTop(SqStack s,SElemType &e){
	if(s.top = s.base ){
		return ERROR;
	}
	e = *(s.top - 1);
	return OK;
}

//在栈是中插入元素e,入栈
Status PushStack(SqStack &s,SElemType e){
	if(s.top - s.base >= s.stacksize){					//若栈满,追加存储空间
		s.base = (SElemType *)realloc(s.base,(s.stacksize + STACKINCREMENT )*sizeof (SElemType ));

		if(!s.base){
			exit(-2);
		}
		s.top = s.base + s.stacksize;
		s.stacksize += STACKINCREMENT;
	}
	*s.top++ = e;
	return OK;
}

//在栈s中删除栈顶,出栈
Status PopStack(SqStack &s,SElemType &e){
	if(s.top == s.base){
		return ERROR;
	}
	e = *--s.top;
	return OK;
}

//判断栈是否为空
Status StackEmpty(SqStack s){
	if(s.base == s.top )
		return OK;
	return ERROR;
}

//销毁栈
Status DestorySatck(SqStack &s){
	free(&s);
	return OK;
}

//初始化迷宫
Status InitMaze(MazeType &maze,int a[ROW][COL],int row,int col){
	int i,j;
	//设置迷宫maze的初值,包括加上边缘一圈的值
	for(i = 1;i<row;i++){
		for(j=1;j<col;j++){
			maze.arr[i][j] = a[i][j];
		}
	}
	//加上围墙
	for(i= 0;i<row;i++){
		maze.arr[0][i] = maze.arr[row-1][i] = 1;		//第0行和第9行为1
	}
	for(j = 0;j<col;j++){
		maze.arr[j][0] = maze.arr[j][col-1] = 1;		//第0列和第9列为1
	}
	return OK;

}

//判断当前节点是否通过,(迷宫数组,当前位置坐标)
Status Pass(MazeType maze,PosType curpos){
	
	//当节点为0时,表示有路
	if(maze.arr[curpos .row][curpos .col] == 0){
		return OK;
	}else {
		return ERROR;
	}

}

//留下标记
Status FootPrint(MazeType &maze,PosType curpos){
	
	maze.arr[curpos.row][curpos .col] = 2;			//走过且走得通
	return OK;

}

//留下不能通过的标记
Status MarkPrint(MazeType &maze,PosType curpos){
	
	maze.arr[curpos .row][curpos .col] = 3;
	return OK;
}


//创建元素e	
SElemType CreateSElem(int step,PosType pos,int di){
	
	SElemType e;
	e.step = step;
	e.seat = pos;
	e.di = di;

	return e;

}

//返回当前节点的下一个节点 (当前位置坐标,下一个位置方向)
PosType NextPos(PosType curpos ,DirectiveType di){

	PosType pos = curpos ;
	switch(di){
		case 1:pos.col++;break;			//右
		case 2:pos.row++;break;			//下
		case 3:pos.col--;break;			//左
		case 4:pos.row--;break;			//上
	}	

	return pos;
}

//判断是不是出口
Status PosEqual(PosType pos1,PosType pos2){
	
	if(pos1.row == pos2.row && pos1.col == pos2.col){
		return OK;
	}else
		return ERROR;

}
	
//打印路径
void PrintMaze(MazeType maze,int row,int col){
	int i,j;
	printf(" ");
    for (i = 0; i<col; i++)                    //打印列数名
       printf("%d ", i);
    printf("\n");
	for (i = 0; i<row; i++){
		 printf("%d",i);                      //打印行数名
       for (j = 0; j<col; j++){
		   //printf("%d ",maze.arr[i][j]);
           switch (maze.arr[i][j]){
				case 0:printf("  "); break;                //没走过,但是通路            
				case 1:printf("■");break;                //墙,障碍物
				case 2:printf("# ");break;              //走过且走得通             
				case 3:printf("* ");break;              //走过但走不通,死胡同               
				default:break;
           }   
       }
       printf("\n");
    }
}

//求解迷宫maze中,从入口start到出口end的一条路径
Status MazePath(MazeType &maze,PosType start,PosType end){
	
	SqStack s;					//定义栈
	SElemType e;
	InitStack (s);				//初始化栈
	PosType curpos = start;
	int curstep = 1;				//搜索第一步
	do{
		 //如果当前位置可以通过,即是未曾走到的路径
		if(Pass(maze,curpos)){
			FootPrint (maze,curpos);		//留下标记
			e = CreateSElem (curstep,curpos,1);		//创建元素
			PushStack(s,e);						//加入路径
			if(PosEqual(curpos,end)){       //判断是不是出口
				return OK;
			}
			curpos = NextPos(curpos,1);			//获取下一个节点,当前位置的右边
			curstep++;
			
		}else{									//当前位置不能通过
			if(!StackEmpty(s)){
				PopStack(s,e);
				while(e.di == 4 && !StackEmpty(s)){   //找寻了四个方向
					MarkPrint(maze,e.seat);
					PopStack(s,e);

				}
				if(e.di<4){
					e.di++;				//换下一个方向
					PushStack(s,e);
					curpos = NextPos (e.seat,e.di);     //设定当前位置是该方向上的相邻块
				}
			}
		}
	}while(!StackEmpty (s));
	
	return OK;
}


Status main(){
	
	int i,j;
	PosType start ,end;			//开始,终点坐标
	MazeType maze;
	int a[ROW][COL] = {
		{1,1,1,1,1,1,1,1,1,1},
		{1,0,0,0,1,0,0,1,0,1},
		{1,0,0,1,0,1,0,1,1,1},
		{1,1,0,0,0,1,0,0,0,1},
		{1,0,1,1,0,0,1,1,0,1},
		{1,1,0,0,1,0,0,0,1,1},
		{1,0,1,0,0,0,1,1,0,1},
		{1,0,1,0,1,1,1,1,0,1},
		{1,1,0,0,0,0,0,0,0,1},
		{1,1,1,1,1,1,1,1,1,1}
	};
	printf("\n原始迷宫如下:\n");
	printf("(其中‘1’表示墙,‘0’表示通道)\n");
    for(i = 0;i < 10;i++){
		for(j = 0;j < 10;j++){
			printf("%d ",a[i][j]);
		}
		printf("\n");
	}

	InitMaze(maze,a,ROW,COL);			//初始化迷宫
	start.row = 1;						//给定迷宫起点坐标(1,1)
	start.col = 1;
	end.row = 8;
	end.col = 8;						//给定迷宫终点坐标(8,8)
	

	if (MazePath(maze, start,end)){             //如果找到一条路径
       printf("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
       printf("\n求解迷宫路径如下:\n");
	   printf("(其中'#'表示求解路径,'*'表示死胡同)\n");

       PrintMaze(maze, ROW,COL);               //输出迷宫路径

    }else 
		printf("\n从入口(1,1)到出口(8,8)没有通路!\n");

	return OK;
}
	

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YJY@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值